package com.vtuzx.kingdee.xqc_core.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.constant.IVtuzxConst;
import com.vtuzx.core.utils.VtuzxUtil;
import com.vtuzx.kingdee.xqc_core.bean.VtuzxArrayList;
import com.vtuzx.kingdee.xqc_core.bean.kingdee.VtuzxKingdeeCloudClient;
import com.vtuzx.kingdee.xqc_core.bean.xqc.BillMaterial;
import com.vtuzx.kingdee.xqc_core.bean.xqc.BillMaterialBox;
import com.vtuzx.kingdee.xqc_core.constant.*;
import com.vtuzx.kingdee.xqc_core.dao.*;
import com.vtuzx.kingdee.xqc_core.service.IJiKeYunApiService;
import com.vtuzx.kingdee.xqc_core.service.IVtuzxBasicService;
import com.vtuzx.kingdee.xqc_core.service.IVtuzxCoreInventoryService;
import com.vtuzx.kingdee.xqc_core.service.IVtuzxKingdeeService;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class VtuzxBasicServiceImpl implements IVtuzxBasicService {

    /**
     * Logger
     */
    private static final Logger _logger = LoggerFactory.getLogger(VtuzxBasicServiceImpl.class);

    @Autowired
    private IVtuzxKingdeeService kingdeeService;



    @Autowired
    private IEzrApiServiceImpl iEzrApiService;

    /**
     * 履历
     */
    @Autowired
    private IntegrationHistoryDao integrationHistoryDao;

    /**
     * 物料
     */
    @Autowired
    private MaterialDao materialDao;

    /**
     * 物料
     */
    @Autowired
    private TraceabilityCodeDetailDao traceabilityCodeDetailDao;

    /**
     * 供应商
     */
    @Autowired
    private SupplierDao supplierDao;

    @Autowired
    private ChannelDao channelDao;

    /**
     * dom
     */
    @Autowired
    private BomDao bomDao;

    /**
     * 仓库
     */
    @Autowired
    private StockDao stockDao;

    /**
     * 仓库
     */
    @Autowired
    private PurOrderDao purOrderDao;

    /**
     * 仓库
     */
    @Autowired
    private CoreParamDao paramDao;

    /**
     * 仓库
     */
    @Autowired
    private PurOrderDetailDao purOrderDetailDao;

    /**
     * 仓库
     */
    @Autowired
    private IJiKeYunApiService jiKeYunApiService;

    /**
     * 仓库
     */
    @Autowired
    private StoreTokenDao storeTokenDao;

    /**
     * 调拨
     */
    @Autowired
    private AllocationDao allocationDao;

    @Autowired
    private IVtuzxCoreInventoryService coreInventoryService;

    /**
     * 调拨
     */
    @Autowired
    private AllocationDetailDao allocationDetailDao;

    /**
     * 调拨
     */
    @Autowired
    private AllocationDetailBoxDao allocationDetailBoxDao;

    /**
     * 即时库存
     */
    @Autowired
    private InventoryDao inventoryDao;

    /**
     * 即时库存
     */
    @Autowired
    private InventoryDetailDao inventoryDetailDao;

    /**
     * 收款单
     */
    @Autowired
    private CollectionDao collectionDao;

    /**
     * 退款单
     */
    @Autowired
    private PaymentDao paymentDao;

    @Autowired
    private PriceListDao priceListDao;

    @Autowired
    private PrdColDetailDao prdColDetailDao;
    /**
     * 销售出库单
     */
    @Autowired
    private SaleOutDao saleOutDao;

    /**
     * 销售出库单
     */
    @Autowired
    private SaleOutDetailDao saleOutDetailDao;

    /**
     * 销售出库单
     **/
    @Autowired
    private SaleOutDetailBoxDao saleOutDetailBoxDao;

    @Autowired
    private IJiKeYunApiService iJiKeYunApiService;

    @Autowired
    private PrdInDao prdInDao;

    @Autowired
    private PrdTaskDao prdTaskDao;

    @Autowired
    private PrdTaskDetailDao prdTaskDetailDao;

    @Autowired
    private InnersettorderDao innersettorderDao;

    @Autowired
    private StorageOutDao storageOutDao;

    @Autowired
    private JikeyunAllocationDao jikeyunAllocationDao;

    @Autowired
    private JikeyunSaleDao jikeyunSaleDao;

    @Autowired
    private PrdInDetailBoxDao prdInDetailBoxDao;

    @Autowired
    private InventoryRegularDao inventoryRegularDao;

    @Autowired
    private InventoryRegularDetailDao inventoryRegularDetailDao;

    @Autowired
    private SyncTaskDao syncTaskDao;

    @Autowired
    private SyncTaskHistoryDao syncTaskHistoryDao;

    @Autowired
    private SelfProductDao selfProductDao;

    @Autowired
    private SelfProductBillDao selfProductBillDao;

    @Autowired
    private WarehouseDao warehouseDao;

    @Autowired
    private GoodsPackageDao goodsPackageDao;

    @Autowired
    private StorageGoodsdocinDao storageGoodsdocinDao;

    public static final Set<String> YEXIANG_WAREHOUSECODE;
    static {
        Set<String> codeSet_YEXIANG_WAREHOUSECODE = new HashSet<>(Arrays.asList(
                "XQWZ00002", "YXQH000004", "XQBB00031", "0009", "YXBB000022",
                "YXBB000017", "YXBB000021", "YXBB000018", "YXBB000020", "YXBB000019",
                "YXBB000010", "YXBB000008", "YXBB000009", "YXBB000003", "YXBB000004",
                "YXBB000006", "YXBB000007", "YXBB000005", "YXBB000002", "YXBB000001"
                //新添加？？？门店仓？？？bb031沃尔玛学苑店-晓芹仓库？？？
                //传百年销售的销售出库？？？客户是大连晓芹？？？

                //YXJDP01 鸡蛋票、油、小米粥总仓-野象  =>  门店仓？？？
                //（组织内）直接调拨单？？？
                ,"XQBB000038"
        ));
        YEXIANG_WAREHOUSECODE = Collections.unmodifiableSet(codeSet_YEXIANG_WAREHOUSECODE);
    }

    public static final Set<String> CHANNEL_WAREHOUSECODE;
    static {
        Set<String> codeSet_CHANNEL_WAREHOUSECODE = new HashSet<>(Arrays.asList(
                "XQBB00071", "XQBB00069", "HZGN", "XQBB00075", "XQWG0036", "YXWB01"
        ));
        CHANNEL_WAREHOUSECODE = Collections.unmodifiableSet(codeSet_CHANNEL_WAREHOUSECODE);
    }

    private static boolean isSpecialWarehouse(String outWarehouseCode, String intWarehouseCode) {
        return isWarehousePair(outWarehouseCode, intWarehouseCode) ||
                isWarehouseCollectionPair(outWarehouseCode, intWarehouseCode);
    }

    private static boolean isWarehousePair(String out, String in) {
        //定义一个Set，包含所有需要双向匹配的仓库代码对（顺序用分隔符连接）
        Set<String> validPairs = new HashSet<>(Arrays.asList(
                "XQBB00066|XQWG00101",
                "XQWG00101|XQBB00066",
                "XQBB00071|XQWG00116",
                "XQWG00116|XQBB00071",
                "XQBBWL01|XQBB00074",
                "XQBB00074|XQBBWL01",
                /*"XQBB00072|XQBB00067",*/
                "XQBB00067|XQ03",
                "XQ03|XQBB00067",
                "YXJDP01|XQBB00074",
                "XQBB00074|YXJDP01",
                "YXJDP01|XQKFB003",
                "XQKFB003|YXJDP01",
                //新添加？？？场景？？？传单？？？
                //XQBB00069=>CHANNEL_WAREHOUSECODE???
                "XQKFB001|XQBB00069"
        ));
        //检查正反两种拼接顺序是否在Set中
        return validPairs.contains(out + "|" + in);
    }

    /**
     * 处理与仓库集合相关的条件判断
     */
    private static boolean isWarehouseCollectionPair(String out, String in) {
        return ("XQBB00074".equals(out) && YEXIANG_WAREHOUSECODE.contains(in)) ||
                ("YXJDP01".equals(out) && YEXIANG_WAREHOUSECODE.contains(in)) ||
                (YEXIANG_WAREHOUSECODE.contains(out) && "XQBB00067".equals(in)) ||
                (YEXIANG_WAREHOUSECODE.contains(out) && "XQ03".equals(in)) ||
                (CHANNEL_WAREHOUSECODE.contains(out) && YEXIANG_WAREHOUSECODE.contains(in)) ||
                (CHANNEL_WAREHOUSECODE.contains(out) && "XQWG00101".equals(in)) ||
                (CHANNEL_WAREHOUSECODE.contains(out) && "YXJDP01".equals(in)) ||
                (YEXIANG_WAREHOUSECODE.contains(out) && YEXIANG_WAREHOUSECODE.contains(in));
    }

    //指定单据集
    /*public static final Set<String> JY;
    static {
        Set<String> codeSet_JY = new HashSet<>(Arrays.asList(
                "JY202508271015"
                //"JY202508260540", "JY202508260982", "JY202508261141", "JY202508261228", "JY202508261277", "JY202508261279", "JY202508261280", "JY202508261281", "JY202508261282", "JY202508261284", "JY202508270004", "JY202508270672", "JY202508270678", "JY202508270680", "JY202508270683", "JY202508270687", "JY202508270690", "JY202508270693", "JY202508270704", "JY202508120656", "JY202508260971", "JY202508270719", "JY202506241296", "JY202508270728", "JY202508270734", "JY202508270737", "JY202508270749", "JY202508270761", "JY202508270767", "JY202508270776", "JY202508270779", "JY202508270783", "JY202508270785", "JY202508270787", "JY202508270808", "JY202508270811", "JY202508270813", "JY202508270819", "JY202508270823", "JY202508270825", "JY202508270828", "JY202508270950", "JY202508270952", "JY202508270953", "JY202508270965", "JY202508270967", "JY202508260955", "JY202508260986", "JY202508261041", "JY202508261042", "JY202508261059", "JY202508261060", "JY202508261061", "JY202508261062", "JY202508261063", "JY202508261043", "JY202508261064", "JY202508261044", "JY202508261065", "JY202508261049", "JY202508261045", "JY202508261066", "JY202508261050", "JY202508261046", "JY202508261051", "JY202508261047", "JY202508261068", "JY202508261048", "JY202508261053", "JY202508261054", "JY202508261055", "JY202508261056", "JY202508261057", "JY202508261058", "JY202508261069", "JY202508261070", "JY202508261071", "JY202508261072", "JY202508261073", "JY202508261074", "JY202508261075", "JY202508261080", "JY202508261076", "JY202508261081", "JY202508261077", "JY202508261082", "JY202508261078", "JY202508261083", "JY202508261084", "JY202508261085", "JY202508261086", "JY202508261088", "JY202508261090", "JY202508261094", "JY202508261105", "JY202508261229", "JY202508261237", "JY202508261238", "JY202508261239", "JY202508261240", "JY202508261241", "JY202508261243", "JY202508261244", "JY202508261245", "JY202508261246", "JY202508261230", "JY202508261231", "JY202508261232", "JY202508261233", "JY202508261247", "JY202508261234", "JY202508261248", "JY202508261235", "JY202508261249", "JY202508261236", "JY202508261250", "JY202508261251", "JY202508261252", "JY202508261253", "JY202508261254", "JY202508261255", "JY202508261256", "JY202508261257", "JY202508261258", "JY202508261259", "JY202508261260", "JY202508261261", "JY202508261262", "JY202508261263", "JY202508261264", "JY202508261265", "JY202508261266", "JY202508261267", "JY202508261268", "JY202508261269", "JY202508261270", "JY202508261272", "JY202508261273", "JY202508261274", "JY202508261275", "JY202508261276", "JY202508261052", "JY202508261271", "JY202508261283", "JY202508270775", "JY202508270831", "JY202508270832", "JY202508270833", "JY202508270834", "JY202508270835", "JY202508270836", "JY202508270837", "JY202508270838", "JY202508270839", "JY202508270840", "JY202508270841", "JY202508270851", "JY202508270842", "JY202508270852", "JY202508270843", "JY202508270853", "JY202508270844", "JY202508270854", "JY202508270845", "JY202508270855", "JY202508270846", "JY202508270856", "JY202508270847", "JY202508270857", "JY202508270848", "JY202508270858", "JY202508270849", "JY202508270859", "JY202508270850", "JY202508270860", "JY202508270861", "JY202508270862", "JY202508270863", "JY202508270864", "JY202508270865", "JY202508270866", "JY202508270867", "JY202508270868", "JY202508270869", "JY202508270870", "JY202508270871", "JY202508270872", "JY202508270873", "JY202508270874", "JY202508270875", "JY202508270876", "JY202508270877", "JY202508270878", "JY202508270879", "JY202508270880", "JY202508270881", "JY202508270882", "JY202508270883", "JY202508270884", "JY202508270885", "JY202508270886", "JY202508270887", "JY202508270888", "JY202508270889", "JY202508270890", "JY202508270901", "JY202508270902", "JY202508270891", "JY202508270892", "JY202508270903", "JY202508270893", "JY202508270904", "JY202508270894", "JY202508270905", "JY202508270895", "JY202508270906", "JY202508270907", "JY202508270896", "JY202508270908", "JY202508270897", "JY202508270898", "JY202508270909", "JY202508270899", "JY202508270910", "JY202508270900", "JY202508270921", "JY202508270911", "JY202508270912", "JY202508270913", "JY202508270914", "JY202508270915", "JY202508270916", "JY202508270918", "JY202508270919", "JY202508270920", "JY202508270922", "JY202508270923", "JY202508270924", "JY202508270925", "JY202508270926", "JY202508270927", "JY202508270928", "JY202508270929", "JY202508270930", "JY202508270917", "JY202508270931", "JY202508270932", "JY202508270933", "JY202508270934", "JY202508270935", "JY202508270936", "JY202508270937", "JY202508270938", "JY202508270939", "JY202508270940", "JY202508270941", "JY202508270942", "JY202508270970", "JY202508270999", "JY202508271011", "JY202508271027", "JY202508271035", "JY202508271036", "JY202508271037", "JY202508271055", "JY202508271041", "JY202508271068", "JY202508270001", "JY202508270002", "JY202508270003", "JY202508270826", "JY202508270943", "JY202508270944", "JY202508271048", "JY202508271122", "JY202508271148", "JY202508271047", "JY202508271058", "JY202508271075", "JY202508271113", "JY202508271117", "JY202508271119", "JY202508271137", "JY202508271158", "JY202508271169", "JY202508271172", "JY202508271176", "JY202508271436", "JY202508271440", "JY202508271471", "JY202508271472", "JY202508271473", "JY202508271474", "JY202508271475", "JY202508271476", "JY202508271477", "JY202508271478", "JY202508271479", "JY202508271508", "JY202508271510", "JY202508271511", "JY202508271513", "JY202508271514", "JY202508271515", "JY202508271516", "JY202508271518", "JY202508271519", "JY202508271522", "JY202508271523", "JY202508271525", "JY202508271526", "JY202508271527", "JY202508271531", "JY202508271532", "JY202508271533", "JY202508271534", "JY202508271535", "JY202508271537", "JY202508271584", "JY202508271586", "JY202508271588", "JY202508271589", "JY202508271590", "JY202508271591", "JY202508271592", "JY202508271596", "JY202508271598", "JY202508271599", "JY202508271619"


        ));
        JY = Collections.unmodifiableSet(codeSet_JY);
    }*/

    @Override
    public void syncMaterial() throws Exception {
        syncMaterial(0, 100);
    }

    /**
     * 同步金蝶物料
     *
     * @param start 开始行
     * @param limit 获取件数
     */
    private void syncMaterial(int start, int limit) throws Exception {
        //先从数据库查询最后一次同步物料的时间
        Document storeToken = storeTokenDao.findOne(Criteria.where("type").is(ConfigType.Kingdee.toString()));
        String lastTime = VtuzxUtil.formatYmd(VtuzxUtil.getObject(storeToken,"lastReloadMaterialTime"));
        String cond = String.format("FCreateDate > '%s' or FModifyDate > '%s'",lastTime,lastTime);
//        String cond = String.format("FNumber = '04030304005'");
        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        List<VtuzxMap> materialQuery = kingdeeService.query(client, "BD_MATERIAL", new VtuzxArrayList<>(
                        "FCreateOrgId.FName", //创建组织
                        "FCreateOrgId.FNumber", //创建组织
                        "FName", //物料名称
                        "FNumber", //物料编码
                        "FSpecification", //规格
                        "FMaterialGroup.FNumber", //物料分组
                        "FMaterialGroup.FName", //物料分组
                        "FTaxRateId.FNumber", //税率编码
                        "FTaxRateId.FName", //税率编码
                        "FDocumentStatus", //状态
                        "FErpClsID", //物料属性
                        "FCreateDate", //创建修改日期
                        "FMATERIALID", //物料内码
                        "FBaseUnitId.FNumber", //基本单位编码
                        "FBaseUnitId.FName", //基本单位名称
                        "F_ora_QYBZQ", //中台是否启用保质期
                        "F_ora_SFTB", //中台是否同步
                        "FCategoryID.FName", //存货类别
                        "FCategoryID.FNumber", //存货类别
                        "F_ora_SFBCP", //是否半成品
                        "F_ora_SFFX", //是否分选
                        "F_ora_kz",//克重
                        "F_ora_BZQTS",//保质期天数
                        "FBaseProperty"//分组编码
                ),
                cond, "FMATERIALID", start, limit);

        for (VtuzxMap material : materialQuery) {
            String fMATERIALID = VtuzxUtil.getString(material, "FMATERIALID");
            String fCreateOrgNumber = VtuzxUtil.getString(material, "FCreateOrgId.FNumber");
            String fCreateOrgName = VtuzxUtil.getString(material, "FCreateOrgId.FName");
            String fUseOrgId = VtuzxUtil.getString(material, "FUseOrgId.FNumber");
            String fName = VtuzxUtil.getString(material, "FName");
            String fNumber = VtuzxUtil.getString(material, "FNumber");
            String fSpecification = VtuzxUtil.getString(material, "FSpecification");
            String fMaterialGroupNumber = VtuzxUtil.getString(material, "FMaterialGroup.FNumber");
            String fMaterialGroupName = VtuzxUtil.getString(material, "FMaterialGroup.FName");
            String fTaxRateNumber = VtuzxUtil.getString(material, "FTaxRateId.FNumber");
            String cateCode = VtuzxUtil.getString(material,"FBaseProperty");
            String fTaxRateName = VtuzxUtil.getString(material, "FTaxRateId.FName");
            String fDocumentStatus = VtuzxUtil.getString(material, "FDocumentStatus");
            String fErpClsID = VtuzxUtil.getString(material, "FErpClsID");
            String fCreateDate = VtuzxUtil.getString(material, "FCreateDate");
            String fBaseUnitIdNumber = VtuzxUtil.getString(material, "FBaseUnitId.FNumber");
            String fBaseUnitIdFName = VtuzxUtil.getString(material, "FBaseUnitId.FName");
            String goodsType = VtuzxUtil.getString(material, "FCategoryID.FName");
            String FCategoryID = VtuzxUtil.getString(material, "FCategoryID.FNumber");
            boolean fOraQYBZQ = VtuzxUtil.getBoolean(material, "F_ora_QYBZQ");
            boolean fOraSFTB = VtuzxUtil.getBoolean(material, "F_ora_SFTB");
            boolean F_ora_SFBCP = VtuzxUtil.getBoolean(material, "F_ora_SFBCP");
            boolean F_ora_SFFX = VtuzxUtil.getBoolean(material, "F_ora_SFFX");
            double F_ora_kz = VtuzxUtil.getDouble(material,"F_ora_kz");
            Integer F_ora_BZQTS = VtuzxUtil.getInt(material,"F_ora_BZQTS");//保质期天数

            Document data = new Document("fMATERIALID", fMATERIALID)
                    .append("fCreateOrgNumber", fCreateOrgNumber)
                    .append("fCreateOrgName", fCreateOrgName)
                    .append("fUseOrgId", fUseOrgId)
                    .append("fName", fName)
                    .append("fNumber", fNumber)
                    .append("fSpecification", fSpecification)
                    .append("fMaterialGroupNumber", fMaterialGroupNumber)
                    .append("fMaterialGroupName", fMaterialGroupName)
                    .append("fTaxRateNumber", fTaxRateNumber)
                    .append("fTaxRateName", fTaxRateName)
                    .append("fDocumentStatus", fDocumentStatus)
                    .append("fErpClsID", fErpClsID)
                    .append("fCreateDate", fCreateDate)
                    .append("fBaseUnitIdNumber", fBaseUnitIdNumber)
                    .append("fBaseUnitIdFName", fBaseUnitIdFName)
                    .append("fOraQYBZQ", fOraQYBZQ)
                    .append("fOraSFTB", fOraSFTB)
                    .append("F_ora_SFBCP", F_ora_SFBCP)
                    .append("F_ora_SFFX", F_ora_SFFX)
                    .append("shelfCount", F_ora_BZQTS)
                    .append("gramCount",F_ora_kz)//克重
                    .append("goodsType", goodsType);

            Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(fNumber));
            if (VtuzxUtil.isEmpty(materialDoc)) {
                materialDao.insertOne(data);
            } else {
                String prdLicence = VtuzxUtil.getString(materialDoc, "prdLicence");
                String prdStandardNo = VtuzxUtil.getString(materialDoc, "prdStandardNo");
                ObjectId id = VtuzxUtil.getObject(materialDoc, IVtuzxConst.Key__id);
                data.append("prdStandardNo", prdStandardNo);
                data.append("prdLicence", prdLicence);
                materialDao.updateById(id, data);
            }

            //同步物料到吉克云(只同步04,05,06的)//同时同步物料到EZR
            if(fNumber.startsWith("04") ||fNumber.startsWith("05") || fNumber.startsWith("06")  ){
                VtuzxMap bizContent = new VtuzxMap("goodsName", fName)
                        .append("goodsNo", fNumber)
                        .append("unitName", fBaseUnitIdFName)
                        .append("outSkuCode", fNumber)
                        .append("skuBarcode", fNumber)
                        .append("skuName",fSpecification)
                        .append("isProductionMaterials",1)//生产物料
                        .append("ownerCode","XQ01")//货主默认晓芹
                        .append("cateCode",cateCode)
                        .append("isBatchManagement",0)//批次管理默认否
                        .append("warehouseCode","XQWG00101");//货品存放仓库默认大连总仓
                Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
                try {
                    jiKeYunApiService.createGoods(storeDoc, bizContent);
                    createMaterialToEzr(data);
                } catch (Exception e){
                    _logger.info(e.getMessage());
                }


            }
            //同步物料到野象04开头以下的不同步
            if(fNumber.startsWith("01") || fNumber.startsWith("02") || fNumber.startsWith("03")){
                continue;
            }
            VtuzxKingdeeCloudClient yeXiangClient = kingdeeService.loginKingdeeYeXiang();//野象
            //查询当前物料是否存在
            //查询单位编码，直接传文字无效
            String materialCond = String.format("FNumber = '%s'", fNumber);
            List<VtuzxMap> bd_material = kingdeeService.query(yeXiangClient, "BD_MATERIAL", new VtuzxArrayList<>(
                    "FNumber",
                    "FNAME"
            ), materialCond);
            //金蝶有物料的话跳过当前循环
            if (bd_material != null && bd_material.size() > 0) {
                continue;
            }
            //查询税率编码
            String taxRateCond = String.format("FName = '%s'", fTaxRateName);
            List<VtuzxMap> taxList = kingdeeService.query(yeXiangClient, "BD_TaxRate", new VtuzxArrayList<>(
                    "FNumber",
                    "FNAME"
            ), taxRateCond);
            String taxNo = "";
            if (!VtuzxUtil.isEmpty(taxList)){
                taxNo = VtuzxUtil.getString(taxList.get(0),"FNumber");
            }

            Map<String, Object> model = new LinkedHashMap<>();//内层model
            Map<String, Object> kneeParam = new LinkedHashMap<>();//保存数据最外层map
            kneeParam.put("NeedUpDateFields", new ArrayList<>());
            kneeParam.put("NeedReturnFields", new ArrayList<>());
            kneeParam.put("IsDeleteEntry", true);
            kneeParam.put("SubSystemId", "");
            kneeParam.put("IsVerifyBaseDataField", true);
            kneeParam.put("IsEntryBatchFill", false);
            kneeParam.put("ValidateFlag", true);
            kneeParam.put("NumberSearch", true);
            kneeParam.put("InterationFlags", "");
            model.put("FCreateOrgId",new Document("FNumber",100));//组织
            model.put("FUseOrgId",new Document("FNumber",200));//组织
            model.put("FNumber",fNumber);//物料编码
            model.put("FName",fName);//物料名称

            model.put("FSpecification",fSpecification);//规格
            model.put("FMaterialGroup",new Document("FNumber",fMaterialGroupNumber));//物料分组

            Map<String,Object> SubHeadEntity = new LinkedHashMap<>();
            SubHeadEntity.put("FErpClsID",fErpClsID);//物料属性
            SubHeadEntity.put("FFeatureItem","1");//特征件子项
            SubHeadEntity.put("FCategoryID",new Document("FNumber",FCategoryID));//存货类别
            SubHeadEntity.put("FBaseUnitId",new Document("FNumber",fBaseUnitIdNumber));//基本单位
            SubHeadEntity.put("FIsPurchase",true);//允许采购
            SubHeadEntity.put("FIsInventory",true);//允许库存
            SubHeadEntity.put("FIsSubContract",true);//允许委外
            SubHeadEntity.put("FIsSale",true);//允许销售
            SubHeadEntity.put("FIsProduce",true);//允许生产
            SubHeadEntity.put("FIsAsset",false);//允许转资产
            SubHeadEntity.put("FWEIGHTUNITID",new Document("FNumber",fBaseUnitIdNumber));//重量单位
            SubHeadEntity.put("FTaxRateId",new Document("FNumber",taxNo));//默认税率
            model.put("SubHeadEntity",SubHeadEntity);
            kneeParam.put("Model", model);
            //创建物料
            try {
                List<VtuzxMap> customerList = kingdeeService.save(yeXiangClient, "BD_MATERIAL", kneeParam);
                VtuzxMap kingdeeCustomerMap = customerList.get(0);
                String number = VtuzxUtil.getString(kingdeeCustomerMap, "Number");
                kingdeeService.submit(yeXiangClient, "BD_MATERIAL", "0", number);
                kingdeeService.audit(yeXiangClient, "BD_MATERIAL", "0", number, "STK_InvCheckResult");
            } catch (Exception e) {
                _logger.info( e.getMessage());
            }
        }
        if (materialQuery.size() >= limit) {
            syncMaterial(start + limit, limit);
        }
    }


    private void createMaterialToEzr(Document data) throws Exception{
        List<Map<String,Object>> materialList = new ArrayList<>();
        Map<String,Object> materialMap = new HashMap<>();
        materialMap.put("Name",VtuzxUtil.getString(data,"fName"));
        materialMap.put("ItemNo",VtuzxUtil.getString(data,"fNumber"));
        List<Map<String,Object>> ProdDetails = new ArrayList<>();
        Map<String,Object> prodMap = new HashMap<>();

        prodMap.put("OutBarCode","");
        prodMap.put("RetailPrice",0);
        prodMap.put("Price",0);
        ProdDetails.add(prodMap);
        List<Map<String,Object>> SpecList = new ArrayList<>();
        Map<String,Object> SpecMap = new HashMap<>();
        SpecMap.put("specCode","FSpecification");
        SpecMap.put("specVal",VtuzxUtil.getString(data,"fSpecification"));
        SpecList.add(SpecMap);
        prodMap.put("SpecList",SpecList);
        prodMap.put("BarCode",VtuzxUtil.getString(data,"fNumber"));

        List<Map<String,Object>> Attrs = new ArrayList<>();
        Map<String,Object> attrsMap1 = new HashMap<>();
        attrsMap1.put("AttrName","物料分组");
        attrsMap1.put("AttrCode","FMaterialGroup");
        List<Map<String,Object>> ProductAttrVal1 = new ArrayList<>();
        Map<String,Object> productAttrValMap1 = new HashMap<>();
        productAttrValMap1.put("AttrVal",VtuzxUtil.getString(data,"fMaterialGroupName"));
        ProductAttrVal1.add(productAttrValMap1);
        attrsMap1.put("ProductAttrVals",ProductAttrVal1);
        Attrs.add(attrsMap1);


        Map<String,Object> attrsMap2 = new HashMap<>();
        attrsMap2.put("AttrName","基本单位");
        attrsMap2.put("AttrCode","FBaseUnitId");
        List<Map<String,Object>> ProductAttrVal2 = new ArrayList<>();
        Map<String,Object> productAttrValMap2 = new HashMap<>();
        productAttrValMap2.put("AttrVal",VtuzxUtil.getString(data,"fBaseUnitIdFName"));
        ProductAttrVal2.add(productAttrValMap2);
        attrsMap2.put("ProductAttrVals",ProductAttrVal2);
        Attrs.add(attrsMap2);

        materialMap.put("ProdDetails",ProdDetails);
        materialMap.put("Attrs",Attrs);
//        materialList.add(materialMap);
        try {
            iEzrApiService.callApi("",materialMap);
        } catch (Exception e){
            throw e;
        }


    }
    @Override
    public void syncSupplier() throws Exception {
        subSyncSupplier(0, 100);
    }

    /**
     * 同步金蝶供应商
     *
     * @param start 开始行
     * @param limit 获取件数
     */
    private void subSyncSupplier(int start, int limit) throws Exception {
        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        String cond = "FDocumentStatus = 'C'";
        List<VtuzxMap> supplierList = kingdeeService.query(client, "BD_Supplier", new VtuzxArrayList<>(
                        "FCreateOrgId.FName", //创建组织
                        "FCreateOrgId.FNumber", //创建组织
                        "FName",
                        "FNumber",
                        "FDocumentStatus",
                        "FForbidStatus",
                        "FCreateDate",
                        "FGroup.FName",
                        "FGroup.FNumber",
                        "FSupplierId",
                        "FShortName",
                        "FRegNumber",
                        "f_ora_pch"
                ),
                cond, "FSupplierId", start, limit);
        for (VtuzxMap supplier : supplierList) {
            String fSupplierId = VtuzxUtil.getString(supplier, "FSupplierId");
            String fCreateOrgNumber = VtuzxUtil.getString(supplier, "FCreateOrgId.FNumber");
            String fCreateOrgName = VtuzxUtil.getString(supplier, "FCreateOrgId.FName");
            String fName = VtuzxUtil.getString(supplier, "FName");
            String fNumber = VtuzxUtil.getString(supplier, "FNumber");
            String fDocumentStatus = VtuzxUtil.getString(supplier, "FDocumentStatus");
            String fForbidStatus = VtuzxUtil.getString(supplier, "FForbidStatus");
            String fGroupFName = VtuzxUtil.getString(supplier, "FGroup.FName");
            String fGroupFNumber = VtuzxUtil.getString(supplier, "FGroup.FNumber");
            String fShortName = VtuzxUtil.getString(supplier, "FShortName");
            String fRegNumber = VtuzxUtil.getString(supplier, "FRegNumber");
            String fCreateDate = VtuzxUtil.getString(supplier, "FCreateDate");
            String f_ora_pch = VtuzxUtil.getString(supplier, "f_ora_pch");

            Document data = new Document("fSupplierId", fSupplierId)
                    .append("f_ora_pch", f_ora_pch)
                    .append("fCreateOrgNumber", fCreateOrgNumber)
                    .append("fCreateOrgName", fCreateOrgName)
                    .append("fForbidStatus", fForbidStatus)
                    .append("fName", fName)
                    .append("fNumber", fNumber)
                    .append("fGroupFName", fGroupFName)
                    .append("fGroupFNumber", fGroupFNumber)
                    .append("fShortName", fShortName)
                    .append("fRegNumber", fRegNumber)
                    .append("fDocumentStatus", fDocumentStatus)
                    .append("isDelete",false)
                    .append("fCreateDate", fCreateDate);

            Document materialDoc = supplierDao.findOne(Criteria.where("fNumber").is(fNumber));
            if (VtuzxUtil.isEmpty(materialDoc)) {
                supplierDao.insertOne(data);
            } else {
                ObjectId id = VtuzxUtil.getObject(materialDoc, IVtuzxConst.Key__id);
                supplierDao.updateById(id, data);

            }


        }
        if (supplierList.size() >= limit) {
            subSyncSupplier(start + limit, limit);
        }
    }

    @Override
    public void syncStock() throws Exception {
        subSyncStock(0, 100);
    }

    /**
     * 同步金蝶仓库
     *
     * @param start 开始行
     * @param limit 获取件数
     */
    private void subSyncStock(int start, int limit) throws Exception {
        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        List<VtuzxMap> stockList = kingdeeService.query(client, "BD_STOCK", new VtuzxArrayList<>(
                        "FCreateOrgId.FName", //创建组织
                        "FCreateOrgId.FNumber", //创建组织
                        "FName",
                        "FNumber",
                        "FDocumentStatus",
                        "FForbidStatus",
                        "FStockProperty",
                        "FStockId",
                        "FCreateDate",
                        "FAddress", //仓库地址
                        "FPrincipal", //仓库负责人
                        "FAllowMinusQty", //是否允许负库存
                        "F_ora_CKYTSX" //是否允许负库存
                ),
                null, "FStockId", start, limit);
        for (VtuzxMap stock : stockList) {
            String fStockId = VtuzxUtil.getString(stock, "FStockId");
            String fCreateOrgNumber = VtuzxUtil.getString(stock, "FCreateOrgId.FNumber");
            String fCreateOrgName = VtuzxUtil.getString(stock, "FCreateOrgId.FName");
            String fName = VtuzxUtil.getString(stock, "FName");
            String fNumber = VtuzxUtil.getString(stock, "FNumber");
            String fDocumentStatus = VtuzxUtil.getString(stock, "FDocumentStatus");
            String fForbidStatus = VtuzxUtil.getString(stock, "FForbidStatus");
            String fStockProperty = VtuzxUtil.getString(stock, "FStockProperty");
            String fCreateDate = VtuzxUtil.getString(stock, "FCreateDate");
            String fAddress = VtuzxUtil.getString(stock, "FAddress");
            String fPrincipal = VtuzxUtil.getString(stock, "FPrincipal");
            String fOraCKYTSX = VtuzxUtil.getString(stock, "F_ora_CKYTSX");
            boolean fAllowMinusQty = VtuzxUtil.getBoolean(stock, "FAllowMinusQty");

            Document data = new Document("fStockId", fStockId)
                    .append("fCreateOrgNumber", fCreateOrgNumber)
                    .append("fCreateOrgName", fCreateOrgName)
                    .append("fForbidStatus", fForbidStatus)
                    .append("fName", fName)
                    .append("fNumber", fNumber)
                    .append("fStockProperty", fStockProperty)
                    .append("fDocumentStatus", fDocumentStatus)
                    .append("fCreateDate", fCreateDate)
                    .append("fAddress", fAddress)
                    .append("fPrincipal", fPrincipal)
                    .append("fOraCKYTSX", fOraCKYTSX)
                    .append("fAllowMinusQty", fAllowMinusQty);

            Document stockDoc = stockDao.findOne(Criteria.where("fNumber").is(fNumber));
            if (VtuzxUtil.isEmpty(stockDoc)) {
                stockDao.insertOne(data);
            } else {
                ObjectId id = VtuzxUtil.getObject(stockDoc, IVtuzxConst.Key__id);
                stockDao.updateById(id, data);
            }
        }
        if (stockList.size() >= limit) {
            subSyncStock(start + limit, limit);
        }
    }


    @Override
    public void syncBom() throws Exception {
        subSyncBom(0, 100);
    }

    /**
     * 同步金蝶仓库
     *
     * @param start 开始行
     * @param limit 获取件数
     */
    private void subSyncBom(int start, int limit) throws Exception {
        //先从数据库查询同步bom的最后日期
        Document storeToken = storeTokenDao.findOne(Criteria.where("type").is(ConfigType.Kingdee.toString()));
        String lastTime = VtuzxUtil.formatYmd(VtuzxUtil.getObject(storeToken,"lastReloadBomTime"));

        String cond = String.format("FCreateDate > '%s' or FModifyDate > '%s'",lastTime,lastTime);
        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        List<VtuzxMap> bomList = kingdeeService.query(client, "ENG_BOM", new VtuzxArrayList<>(
                        "FCreateOrgId.FName", //创建组织
                        "FCreateOrgId.FNumber", //创建组织
                        "FName",
                        "FNumber",
                        "FDocumentStatus",
                        "FForbidStatus",
                        "FID",
                        "FMATERIALID.FNumber",//父项物料编码
                        "FUNITID.FNumber",//父项物料单位
                        "FUNITID.FName",//父项物料单位
                        "FITEMNAME",//物料名称
                        "FITEMMODEL",//规格型号
                        "FITEMPPROPERTY",//物料属性
                        "FMATERIALIDCHILD.FNumber",//子项物料编码
                        "FCHILDITEMNAME",//子项物料名称
                        "FCHILDITEMMODEL",//子项规格型号
                        "FMATERIALTYPE",//子项类型
                        "FCHILDUNITID.FNumber",//子项单位
                        "FCHILDUNITID.FName",//子项单位
                        "FCHILDITEMPROPERTY",//子项物料属性
                        "FSCRAPRATE",//变动损耗率%
                        "FNUMERATOR",//用量:分子
                        "FDENOMINATOR"//用量:分母
//                        "F_ora_ZTPX"//用来排序
                ),
                cond, "FID", start, limit);
        for (VtuzxMap bom : bomList) {
            List<VtuzxMap> childList = new ArrayList<>();
            VtuzxMap child = new VtuzxMap();
            String fId = VtuzxUtil.getString(bom, "FID");
            String fCreateOrgNumber = VtuzxUtil.getString(bom, "FCreateOrgId.FNumber");
            String fCreateOrgName = VtuzxUtil.getString(bom, "FCreateOrgId.FName");
            String fName = VtuzxUtil.getString(bom, "FName");
            String fNumber = VtuzxUtil.getString(bom, "FNumber");
            String fDocumentStatus = VtuzxUtil.getString(bom, "FDocumentStatus");
            String materialNo = VtuzxUtil.getString(bom, "FMATERIALID.FNumber");
            String unitNumber = VtuzxUtil.getString(bom, "FUNITID.FNumber");
            String unitName = VtuzxUtil.getString(bom, "FUNITID.FName");
            String materialName = VtuzxUtil.getString(bom, "FITEMNAME");
            String materialModel = VtuzxUtil.getString(bom, "FITEMMODEL");
            String materialProperty = VtuzxUtil.getString(bom, "FITEMPPROPERTY");
            String childMaterialNo = VtuzxUtil.getString(bom, "FMATERIALIDCHILD.FNumber");
            String childMaterialName = VtuzxUtil.getString(bom, "FCHILDITEMNAME");
            String childMaterialModel = VtuzxUtil.getString(bom, "FCHILDITEMMODEL");
            String childMaterialType = VtuzxUtil.getString(bom, "FMATERIALTYPE");
            String childUnitNumber = VtuzxUtil.getString(bom, "FCHILDUNITID.FNumber");
            String childUnitName = VtuzxUtil.getString(bom, "FCHILDUNITID.FName");
            String childMaterialProperty = VtuzxUtil.getString(bom, "FCHILDITEMPROPERTY");
            String scraprate = VtuzxUtil.getString(bom, "FSCRAPRATE");
            String numerator = VtuzxUtil.getString(bom, "FNUMERATOR");
            String denominator = VtuzxUtil.getString(bom, "FDENOMINATOR");
//            String orderNum = VtuzxUtil.getString(bom, "F_ora_ZTPX");
//            int order = 0;
//            if (!VtuzxUtil.isEmpty(orderNum)) {
//                order = Integer.parseInt(orderNum);
//            }

            child.append("childMaterialNo", childMaterialNo)
                    .append("childMaterialName", childMaterialName)
                    .append("childMaterialModel", childMaterialModel)
                    .append("childMaterialType", childMaterialType)
                    .append("childUnitNumber", childUnitNumber)
                    .append("childUnitName", childUnitName)
                    .append("numerator", numerator)
                    .append("denominator", denominator)
                    .append("childMaterialProperty", childMaterialProperty)
                    .append("scraprate", scraprate);
            childList.add(child);

            Document data = new Document("fId", fId)
                    .append("fCreateOrgNumber", fCreateOrgNumber)
                    .append("fCreateOrgName", fCreateOrgName)
                    .append("fDocumentStatus", fDocumentStatus)
                    .append("fName", fName)
                    .append("fNumber", fNumber)
                    .append("materialNo", materialNo)
                    .append("materialName", materialName)
                    .append("materialModel", materialModel)
                    .append("unitNumber", unitNumber)
                    .append("unitName", unitName)
                    .append("materialProperty", materialProperty)
                    .append("childList", childList);


            Document bomDoc = bomDao.findOne(Criteria.where("fId").is(fId).and("materialNo").is(materialNo));
            if (VtuzxUtil.isEmpty(bomDoc)) {
                bomDao.insertOne(data);
            } else {
                ObjectId id = VtuzxUtil.getObject(bomDoc, IVtuzxConst.Key__id);
                List<VtuzxMap> bomChildList = VtuzxUtil.getObject(bomDoc, "childList");
                if (!bomChildList.contains(child)) {
                    bomChildList.add(child);
                }
                bomDao.updateById(id, data);
            }
        }
        if (bomList.size() >= limit) {
            subSyncBom(start + limit, limit);
        }
    }

    @Override
    public void syncPurOrder() throws Exception {
        subPurOrder(0, 100);
    }

    private void subPurOrder(int start, int limit) throws Exception {
        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        List<VtuzxMap> purchaseOrderList = kingdeeService.query(client, "PUR_PurchaseOrder", new VtuzxArrayList<>(
                        "FBillTypeID.FNumber", //单据类型
                        "FBillNo", //采购单号
                        "FContractNo", //合同号
                        "FDocumentStatus", //状态
                        "FDate", //日期
                        "FPurchaseDeptId.FNumber", //采购部门
                        "FPurchaseDeptId.FName", //采购部门
                        "FPurchaserId.FNumber", //采购员
                        "FPurchaserId.FName", //采购员
                        "FSupplierId.FNumber", //供应商
                        "FSupplierId.FName", //供应商
                        "FSettleId.FNumber", //结算方
                        "FChargeId.FNumber", //收款方
                        "FPOOrderEntry_FEntryID", //分录id
                        "FMaterialId.FNumber", //物料编码
                        "FMaterialName", //物料名称
                        "FModel", //物料名称
                        "FLot.FNumber", //批次号
                        "FUnitId.FNumber", //采购单位
                        "FUnitId.FName", //采购单位
                        "FQty", //采购数量
                        "FPriceUnitId.FNumber", //计价单位
                        "FPriceUnitId.FName", //计价单位
                        "FDeliveryDate", //交货日期
                        "FPrice", //单价
                        "FTaxPrice", //含税单价
                        "FEntryDiscountRate", //折扣率
                        "FEntryAmount", //金额
                        "FEntryTaxRate", //税率
                        "FBillTaxAmount", //税额
                        "FAllAmount", //价税合计
                        "FGiveAway", //是否赠品
                        "FModifyDate" // 最后修改日期
                ),
                null, "FID", start, limit);
        if (VtuzxUtil.isEmpty(purchaseOrderList)) return;

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        DateFormat dfTwo = new SimpleDateFormat("yyyy-MM-dd'T'");
        for (VtuzxMap purchaseOrder : purchaseOrderList) {
            String billNo = VtuzxUtil.getString(purchaseOrder, "FBillNo");
            String entryId = VtuzxUtil.getString(purchaseOrder, "FPOOrderEntry_FEntryID");
            String contractNo = VtuzxUtil.getString(purchaseOrder, "FContractNo");
            String orderType = VtuzxUtil.getString(purchaseOrder, "FBillTypeID.FNumber");
            String purchaseDate = VtuzxUtil.formatYmdF(dfTwo.parse(VtuzxUtil.getString(purchaseOrder, "FDate")));
            String purchaseDept = VtuzxUtil.getString(purchaseOrder, "FPurchaseDeptId.FNumber");
            String purchaseDeptName = VtuzxUtil.getString(purchaseOrder, "FPurchaseDeptId.FName");
            String purchaser = VtuzxUtil.getString(purchaseOrder, "FPurchaserId.FNumber");
            String purchaserName = VtuzxUtil.getString(purchaseOrder, "FPurchaserId.FName");
            String supplierNo = VtuzxUtil.getString(purchaseOrder, "FSupplierId.FNumber");
            String supplierName = VtuzxUtil.getString(purchaseOrder, "FSupplierId.FName");
            String settle = VtuzxUtil.getString(purchaseOrder, "FSettleId.FNumber");
            String charge = VtuzxUtil.getString(purchaseOrder, "FChargeId.FNumber");
            String materialNo = VtuzxUtil.getString(purchaseOrder, "FMaterialId.FNumber");
            String materialName = VtuzxUtil.getString(purchaseOrder, "FMaterialName");
            String materialSpec = VtuzxUtil.getString(purchaseOrder, "FModel");
            String batchNo = VtuzxUtil.getString(purchaseOrder, "FLot.FNumber");
            String purchaseUnitName = VtuzxUtil.getString(purchaseOrder, "FUnitId.FName");
            double qty = VtuzxUtil.getObject(purchaseOrder, "FQty");
            String calcUnitName = VtuzxUtil.getString(purchaseOrder, "FPriceUnitId.FName");
            Date deliveryDate = dfTwo.parse(VtuzxUtil.getString(purchaseOrder, "FDeliveryDate"));
            double price = VtuzxUtil.getObject(purchaseOrder, "FPrice");
            double taxPrice = VtuzxUtil.getObject(purchaseOrder, "FTaxPrice");
            double discountRate = VtuzxUtil.getObject(purchaseOrder, "FEntryDiscountRate");
            double amount = VtuzxUtil.getObject(purchaseOrder, "FEntryAmount");
            double taxRate = VtuzxUtil.getObject(purchaseOrder, "FEntryTaxRate");
            double tax = VtuzxUtil.getObject(purchaseOrder, "FBillTaxAmount");
            double taxAmount = VtuzxUtil.getObject(purchaseOrder, "FAllAmount");
            boolean isGift = VtuzxUtil.getObject(purchaseOrder, "FGiveAway");
            Date modifyDate = df.parse(VtuzxUtil.getString(purchaseOrder, "FModifyDate"));

            Document headerDoc = new Document("orderNo", billNo)
                    .append("billNo", contractNo)
                    .append("orderType", orderType)
                    .append("status", BillStatus.Audit.toString())
                    .append("purchaseDate", purchaseDate)
                    .append("purchaseDept", purchaseDept)
                    .append("purchaseDeptName", purchaseDeptName)
                    .append("purchaser", purchaser)
                    .append("purchaserName", purchaserName)
                    .append("supplierNo", supplierNo)
                    .append("supplierName", supplierName)
                    .append("settle", settle)
                    .append("charge", charge)
                    .append("modifyDate", VtuzxUtil.formatYmdHmsF(modifyDate));

            Criteria cond = new Criteria("orderNo").is(billNo).and("billNo").is(contractNo);
            Document billDoc = purOrderDao.findOne(cond);
            if (!VtuzxUtil.isEmpty(billDoc)) {
                String headerModifyDate = VtuzxUtil.getString(billDoc, "modifyDate");
                if (!headerModifyDate.equals(VtuzxUtil.formatYmdHmsF(modifyDate))) { //如果这个订单修改过 就删掉重新加
                    purOrderDao.deleteOne(cond);
                    purOrderDetailDao.deleteMany(cond);
                }
            } else {
                purOrderDao.insertOne(headerDoc);
            }

            Document detailDoc = new Document("orderNo", billNo)
                    .append("billNo", contractNo)
                    .append("entryId", entryId)
                    .append("materialNo", materialNo)
                    .append("materialName", materialName)
                    .append("materialSpec", materialSpec)
                    .append("batchNo", batchNo)
                    .append("purchaseUnitName", purchaseUnitName)
                    .append("calcUnitName", calcUnitName)
                    .append("deliveryDate", deliveryDate)
                    .append("taxRate", taxRate)
                    .append("qty", qty)
                    .append("unSettlementQty", qty)
                    .append("price", price)
                    .append("amount", amount)
                    .append("discountRate", discountRate)
                    .append("taxPrice", taxPrice)
                    .append("taxAmount", taxAmount)
                    .append("tax", tax)
                    .append("isGift", isGift ? "1" : "0");
            Document purDetailDoc = purOrderDetailDao.findOne(Criteria.where("orderNo").is(billNo).and("entryId").is(entryId));
            if (VtuzxUtil.isEmpty(purDetailDoc)) {
                purOrderDetailDao.insertOne(detailDoc);
            }
        }
        if (purchaseOrderList.size() >= limit) {
            subPurOrder(start + limit, limit);
        }
    }


    /**
     * 同步吉克云客户
     *
     * @param from
     * @param to
     * @param pageIndex
     * @throws Exception
     */
    @Override
    public void syncCustomer(Date from, Date to, int pageIndex) throws Exception {
        //获取吉克云客户
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap customerMap = jiKeYunApiService.customerList(storeDoc,
                new VtuzxMap("gmtCreateBegin", VtuzxUtil.formatYmdHmsF(from))
                        .append("gmtCreateEnd", VtuzxUtil.formatYmdHmsF(to))
                        .append("pageSize", 50)
                        .append("pageIndex", pageIndex));
        Map<String, Object> result = VtuzxUtil.getObject(customerMap, "result");
        List<Map<String, Object>> dataList = VtuzxUtil.getObject(result, "data");
        if (dataList.size() <= 0) {
            return;
        }
//        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        VtuzxKingdeeCloudClient clientYX = kingdeeService.loginKingdeeYeXiang();
        for (Map<String, Object> data : dataList) {
            String customerCode = VtuzxUtil.getString(data, "customerCode");
            String nickname = VtuzxUtil.getString(data, "nickname");
            Map<String, Object> customerParam = new LinkedHashMap<>();
            Map<String, Object> customerModel = new LinkedHashMap<>();
            customerModel.put("FNumber", customerCode);
            customerModel.put("FName", nickname);

            customerParam.put("NeedUpDateFields", new ArrayList<>());
            customerParam.put("NeedReturnFields", new ArrayList<>());
            customerParam.put("IsDeleteEntry", true);
            customerParam.put("SubSystemId", "");
            customerParam.put("IsVerifyBaseDataField", true);
            customerParam.put("IsEntryBatchFill", false);
            customerParam.put("ValidateFlag", true);
            customerParam.put("NumberSearch", true);
            customerParam.put("InterationFlags", "");
            customerParam.put("Model", customerModel);
            try {
                List<VtuzxMap> customerList = kingdeeService.save(clientYX, "BD_Customer", customerParam);
                VtuzxMap kingdeeCustomerMap = customerList.get(0);
                String number = VtuzxUtil.getString(kingdeeCustomerMap, "Number");
                kingdeeService.submit(clientYX, "BD_Customer", "0", number);
                kingdeeService.audit(clientYX, "BD_Customer", "0", number);
            } catch (Exception e) {
                _logger.info(e.getMessage());
            }
        }
        syncCustomer(from, to, pageIndex + 1);
    }

    public VtuzxMap getParameters(Map<String, Object> param) {
        List<String> keys = VtuzxUtil.getObject(param, "keys");
        Iterator<Document> docList = paramDao.findList(Criteria.where("key").in(keys).and("effect").is(true), (Document) null, 0, 0);
        VtuzxMap retMap = new VtuzxMap();
        while (docList.hasNext()) {
            Document doc = docList.next();
            VtuzxMap data = new VtuzxMap();
            String key = VtuzxUtil.getString(doc, "key");
            data.put("key", key);
            data.put("name", VtuzxUtil.getString(doc, "name"));
            data.put("value", VtuzxUtil.getString(doc, "value"));
            retMap.put(key, data);
        }
        return retMap;
    }

    /**
     * 同步吉克云调拨单
     *
     * @param from
     * @param to
     * @param pageIndex
     */
    @Override
    public void syncAllocation(Date from, Date to, int pageIndex) throws Exception {
//        VtuzxMap sysParamMap = getParameters(new VtuzxMap("keys", new VtuzxArrayList<>("traceabilityCodeUrl")));
//        VtuzxMap traceabilityCodeUrlMap = VtuzxUtil.getObject(sysParamMap, "traceabilityCodeUrl");
//        if (traceabilityCodeUrlMap == null) {
//            throw new VtuzxException(IXqcConst.Msg_E_system);
//        }

        //获取吉克云调拨单数据
        System.out.println(pageIndex);
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap customerMap = jiKeYunApiService.allocationList(storeDoc,
//                new VtuzxMap("allocateNos","DB202505300022"));
                new VtuzxMap("modifyStartDate", VtuzxUtil.formatYmdHmsF(from))//修改时间
                        .append("modifyEndDate", VtuzxUtil.formatYmdHmsF(to))
                        .append("pageSize", 50)
                        .append("outstatus", "3")//出库状态已完成
                        .append("pageIndex", pageIndex));
        Map<String, Object> result = VtuzxUtil.getObject(customerMap, "result");
        Map<String, Object> data = VtuzxUtil.getObject(result, "data");
        List<Map<String, Object>> stockAllocateList = VtuzxUtil.getObject(data, "stockAllocate");
        if (stockAllocateList.size() <= 0) {
            return;
        }
        //中台保存
        for (Map<String, Object> stockAllocate : stockAllocateList) {
            String allocateNo = VtuzxUtil.getString(stockAllocate, "allocateNo"); //调拨单号
            String intWarehouseName = VtuzxUtil.getString(stockAllocate,"intWarehouseName");//调入仓库名称
            String outWarehouseName = VtuzxUtil.getString(stockAllocate,"outWarehouseName");//调出仓库
            String outWarehouseCode = VtuzxUtil.getString(stockAllocate,"outWarehouseCode");//调出仓库编号
            Long gmtCreate = VtuzxUtil.getLong(stockAllocate,"gmtCreate");//创建时间
            Document allocationDoc = new Document();//保存极客云调拨单
            allocationDoc.append("allocateNo",VtuzxUtil.getString(stockAllocate, "allocateNo"))
                    .append("allocateId",VtuzxUtil.getString(stockAllocate, "allocateId"))
                    .append("outWarehouseId",VtuzxUtil.getString(stockAllocate, "outWarehouseId"))
                    .append("inWarehouseId",VtuzxUtil.getString(stockAllocate, "inWarehouseId"))
                    .append("outWarehouseName",VtuzxUtil.getString(stockAllocate, "outWarehouseName"))
                    .append("intWarehouseName",VtuzxUtil.getString(stockAllocate, "intWarehouseName"))
                    .append("allocateType",VtuzxUtil.getString(stockAllocate, "allocateType"))
                    .append("allocateTypeName",VtuzxUtil.getString(stockAllocate, "allocateTypeName"))
                    .append("applyUserId",VtuzxUtil.getString(stockAllocate, "applyUserId"))
                    .append("applyUserName",VtuzxUtil.getString(stockAllocate, "applyUserName"))
                    .append("applyDepartId",VtuzxUtil.getString(stockAllocate, "applyDepartId"))
                    .append("applyDepartName",VtuzxUtil.getString(stockAllocate, "applyDepartName"))
                    .append("applyDate",VtuzxUtil.getLong(stockAllocate, "applyDate"))
                    .append("operator",VtuzxUtil.getString(stockAllocate, "operator"))
                    .append("operatorId",VtuzxUtil.getString(stockAllocate, "operatorId"))
                    .append("auditUserId",VtuzxUtil.getString(stockAllocate, "auditUserId"))
                    .append("auditUserName",VtuzxUtil.getString(stockAllocate, "auditUserName"))
                    .append("auditDate",VtuzxUtil.getLong(stockAllocate, "auditDate"))
                    .append("status",VtuzxUtil.getString(stockAllocate, "status"))
                    .append("outStatus",VtuzxUtil.getString(stockAllocate, "outStatus"))
                    .append("inStatus",VtuzxUtil.getString(stockAllocate, "inStatus"))
                    .append("memo",VtuzxUtil.getString(stockAllocate, "memo"))
                    .append("goodsCount",VtuzxUtil.getInt(stockAllocate, "goodsCount"))
                    .append("skuCount",VtuzxUtil.getInt(stockAllocate, "skuCount"))
                    .append("gmtCreate",VtuzxUtil.getLong(stockAllocate, "gmtCreate"))
                    .append("companyName",VtuzxUtil.getString(stockAllocate, "companyName"))
                    .append("stockAllocateDetailViews",VtuzxUtil.getObject(stockAllocate, "stockAllocateDetailViews"))
                    .append("inCountSum",VtuzxUtil.getInt(stockAllocate, "inCountSum"))
                    .append("outCountSum",VtuzxUtil.getInt(stockAllocate, "outCountSum"))
                    .append("outWarehouseCode",VtuzxUtil.getString(stockAllocate, "outWarehouseCode"))
                    .append("intWarehouseCode",VtuzxUtil.getString(stockAllocate, "intWarehouseCode"))
                    .append("billNo",IXqcConst.createBillNo(BillType.JKYDB))
                    .append("isUpload","no");
            Document jackAllocaeDoc = jikeyunAllocationDao.findOne(Criteria.where("allocateNo").is(allocateNo));
            if (VtuzxUtil.isEmpty(jackAllocaeDoc)){//如果没添加过
                jikeyunAllocationDao.insertOne(allocationDoc);//添加到极客云调拨表
                _logger.info(String.format("添加吉客云调拨单号%s",allocateNo));
            } else {
                jikeyunAllocationDao.updateOne(Criteria.where("allocateNo").is(allocateNo),allocationDoc);
                _logger.info(String.format("修改吉客云调拨单号%s",allocateNo));
//                continue;
            }


            VtuzxMap param = new VtuzxMap();//先从出库单查询是否有唯一码
            String selelctFields = "goodsDocDetailList.goodsId,goodsDocDetailList.goodsNo,goodsDocDetailList.serialNo,goodsDocDetailList.quantity";
            param.append("pageSize",1)
                    .append("pageIndex",0)
                    .append("selelctFields",selelctFields)
                    .append("sourceBillNo",allocateNo);
            VtuzxMap stotrageDoc = jiKeYunApiService.getStorageOut(storeDoc, param);
            Map<String, Object> storageResult = VtuzxUtil.getObject(stotrageDoc, "result");
            List<Map<String, Object>> storageData = VtuzxUtil.getObject(storageResult, "data");
            List<Map<String, Object>> goodsDocDetailList = new ArrayList<>();
            if (!VtuzxUtil.isEmpty(storageData)){
                goodsDocDetailList = VtuzxUtil.getObject(storageData.get(0),"goodsDocDetailList");
            }

//            String outWarehouseCode = VtuzxUtil.getString(stockAllocate, "outWarehouseCode"); //调出仓库编号
            String intWarehouseCode = VtuzxUtil.getString(stockAllocate, "intWarehouseCode");//调入仓库编号
            List<String> materialNoList = new ArrayList<>(); //去数据库查询的物料
            VtuzxMap materialCountMap = new VtuzxMap(); //需要出库的物料和数量
            List<String> traceCodeList = new ArrayList<>();
            List<VtuzxMap> materialSerialList = new ArrayList<>();//物料和对应的唯一码
            for (Map<String,Object> goodsMap: goodsDocDetailList){
                String serialNo = VtuzxUtil.getString(goodsMap,"serialNo");
                String goodsNo = VtuzxUtil.getString(goodsMap,"goodsNo");
                if (!VtuzxUtil.isEmpty(serialNo)){//如果有唯一码的话
                    if (serialNo.startsWith("HTTP://ZS")){
                        StringBuilder sb = new StringBuilder(serialNo.toLowerCase());
                        sb.setCharAt(49,'Z');
                        sb.setCharAt(44,'C');
                        String newSerialNo = sb.toString();
                        traceCodeList.add(newSerialNo);
                        VtuzxMap map = new VtuzxMap("goodsNo",goodsNo)
                                .append("traceBackNo",newSerialNo);
                        materialSerialList.add(map);
                        Document serialDoc = new Document();
                        serialDoc.append("issue",outWarehouseName)//发出方对应出库仓库
                                .append("saleChnnel",intWarehouseName)//销售渠道
                                .append("lastTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//销售时间
                                .append("allocateTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//调拨时间
                                .append("allocateNo",allocateNo)
                                .append("receive",intWarehouseName);//接收方对应调入仓库
                        traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo),serialDoc);
                        _logger.info(String.format("追溯链接收和发出[%s]",newSerialNo));
                        System.out.println("追溯链" + newSerialNo);
                        //给唯一码添加供应链信息
                        if ("XQBBWL01".equals(outWarehouseCode)){//调出仓库是本埠物流仓库，取调入仓库添加追溯链销售渠道
                            Document updateDoc = new Document();
                            updateDoc.append("saleChnnel",intWarehouseName)//销售渠道
                                    .append("allocateTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//调拨时间
                                    .append("lastTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//销售时间
                                    .append("allocateNo",allocateNo);//调拨单号
                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo),updateDoc);
                            _logger.info(String.format("添加追溯链信息[%s]",newSerialNo));
                        }
                        if ("XQKFB003".equals(outWarehouseCode)){//调出仓库是客服仓库销售渠道是客服部
                            Document updateDoc = new Document();
                            updateDoc.append("saleChnnel","客服部")//销售渠道
                                    .append("allocateTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//调拨时间
                                    .append("lastTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//销售时间
                                    .append("allocateNo",allocateNo);//调拨单号
                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo),updateDoc);
                            _logger.info(String.format("添加追溯链信息[%s]",newSerialNo));
                        }
                        if ("XQWG00115".equals(outWarehouseCode) || "XQWG00102".equals(outWarehouseName)){//调出仓库是电商部物流备货仓或者大连电商京东备货仓，销售渠道是网购部
                            Document updateDoc = new Document();
                            updateDoc.append("saleChnnel","网购部")//销售渠道
                                    .append("allocateTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//调拨时间
                                    .append("lastTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//销售时间
                                    .append("allocateNo",allocateNo);//调拨单号
                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo),updateDoc);
                            _logger.info(String.format("添加追溯链信息[%s]",newSerialNo));
                        }
                        if ("HZGNBH".equals(outWarehouseCode) ){//调出仓库是杭州光年备货仓
                            Document updateDoc = new Document();
                            updateDoc.append("saleChnnel","杭州光年")//销售渠道
                                    .append("allocateTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//调拨时间
                                    .append("lastTime",VtuzxUtil.formatYmdHmsF(new Date(gmtCreate)))//销售时间
                                    .append("allocateNo",allocateNo);//调拨单号
                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo),updateDoc);
                            _logger.info(String.format("添加追溯链信息[%s]",newSerialNo));
                        }

                    }

                } else {
                    materialNoList.add(goodsNo);
                    double skuCount = VtuzxUtil.getDouble(goodsMap,"quantity");
                    double count = VtuzxUtil.getDouble(materialCountMap, goodsNo);
                    materialCountMap.append(goodsNo,  count + skuCount);
                }
            }
            List<String> getBoxNoList = new ArrayList<>();
            List<Document> zsBoxList = new ArrayList<>();
            Iterator<Document> traceabilityCodeDetailItr = traceabilityCodeDetailDao.findList(Criteria.where("traceabilityCode").in(traceCodeList), null, 0, 0);
            while (traceabilityCodeDetailItr.hasNext()) {
                Document traceabilityCodeDetailDoc = traceabilityCodeDetailItr.next();
                getBoxNoList.add(VtuzxUtil.getString(traceabilityCodeDetailDoc, "boxNo"));
                zsBoxList.add(new Document("traceBack", VtuzxUtil.getString(traceabilityCodeDetailDoc, "traceabilityCode")).append("boxNo", VtuzxUtil.getString(traceabilityCodeDetailDoc, "boxNo")));
            }
            VtuzxMap materialData = new VtuzxMap();
            Iterator<Document> materialItr = materialDao.findList(Criteria.where("fNumber").in(materialNoList), null, 0, 0);
            while (materialItr.hasNext()) {
                Document materialDoc = materialItr.next();
                String fNumber = VtuzxUtil.getString(materialDoc, "fNumber");
                materialData.append(fNumber, materialDoc);
            }
            if (intWarehouseCode.equals("XQWG00116") ) { //如果调入仓库是网购发货仓存中台调拨单，
                List<ObjectId> allIdList = new ArrayList<>();
                VtuzxMap allMaterialCountMap = new VtuzxMap();
                List<Document> invDocList = new ArrayList<>();
                VtuzxMap invDataMap = new VtuzxMap();
                Criteria invCond = new Criteria();
                invCond.and("materialNo").in(materialNoList).and("count").gt(0);
                Iterator<Document> invItr = inventoryDao.findList(invCond, null, 0, 0);
                while (invItr.hasNext()) {
                    Document invDoc = invItr.next();
                    String id = VtuzxUtil.getString(invDoc, "_id");
                    invDataMap.append(id, invDoc);
                    invDocList.add(invDoc);
                }

                for (Map.Entry entry:materialCountMap.entrySet() ){
                    for (Document invDoc : invDocList) {
                        boolean isDelete = VtuzxUtil.getBoolean(invDoc, "isDelete");
                        if (!isDelete) {
                            ObjectId id = VtuzxUtil.getObject(invDoc, "_id");
                            String materialNo = (String) entry.getKey();
                            String ztMaterialNo = VtuzxUtil.getString(invDoc,"materialNo");
                            if (materialNo.equals(ztMaterialNo)){
                                double count = VtuzxUtil.getDouble(invDoc, "count");
                                double jiKeYunCount = VtuzxUtil.getDouble(materialCountMap, materialNo);
                                if (jiKeYunCount > count) { //即时库存分录数量全部出库
                                    materialCountMap.append(materialNo, jiKeYunCount - count); //吉克云还有多少需要出库
                                    allMaterialCountMap.append(id.toString(), count); //这条全部出库
                                    invDoc.append("isDelete", true);
                                    allIdList.add(id);
                                } else { //即时库存分录部分数量出库
                                    allMaterialCountMap.append(id.toString(), jiKeYunCount);
                                    invDoc.append("count", count - jiKeYunCount);
                                    allIdList.add(id);
                                    break;
                                }
                            }
                        }
                    }
                }
                List<Document> invDetailList = new ArrayList<>();
                Criteria cond = new Criteria();
                cond.orOperator(Criteria.where("boxNo").in(getBoxNoList), Criteria.where("_inventoryId").in(allIdList).and("status").is("in"));
                Iterator<Document> invDetailItr = inventoryDetailDao.findList(cond, null, 0, 0);
                while (invDetailItr.hasNext()) {
                    Document invDetailDoc = invDetailItr.next();
                    invDetailList.add(invDetailDoc);
                }
                VtuzxMap materialDetailMap = new VtuzxMap();
                List<BillMaterial> billMaterialList = new ArrayList<>();//入库
                for (Map.Entry entry : allMaterialCountMap.entrySet()){//k:id , v:这个id所需的数量
                    List<VtuzxMap> outStockBoxNoList = new ArrayList<>();
                    double needCount = (double) entry.getValue();
                    String id = entry.getKey().toString();
                    for (Document invDetail : invDetailList) {
                        if (!VtuzxUtil.getBoolean(invDetail, "isDelete")) {
                            double invDetailCount = VtuzxUtil.getDouble(invDetail, "count");
                            String boxNo = VtuzxUtil.getString(invDetail, "boxNo");
                            String locationNo = VtuzxUtil.getString(invDetail, "locationNo");
                            String rfid = VtuzxUtil.getString(invDetail, "rfid");
                            String stockNo = VtuzxUtil.getString(invDetail,"stockNo");
                            String _inventoryId = VtuzxUtil.getString(invDetail,"_inventoryId");
                            if (id.equals(_inventoryId)){
                                BillMaterial billMaterial = new BillMaterial();//入库参数
                                Document invDataDoc = invDataMap.getObject(_inventoryId);
                                billMaterial.setMaterialNo(VtuzxUtil.getString(invDataDoc,"materialNo"));
                                billMaterial.setUnit(VtuzxUtil.getString(invDataDoc,"unit"));
                                billMaterial.setBatchNo(VtuzxUtil.getString(invDataDoc,"batchNo"));
                                billMaterial.setProduceDate(VtuzxUtil.formatYmdHmsF(new Date()));
                                billMaterial.setExp(VtuzxUtil.getInt(invDataDoc,"exp"));
                                List<BillMaterialBox> boxList = new ArrayList<>();
                                BillMaterialBox box = new BillMaterialBox();
                                box.setBoxNo("A02" + new Date().getTime());
                                box.setCount(needCount);
                                box.setLocationNo("FH001");
                                box.setIsTaskIn(true);
                                boxList.add(box);
                                billMaterial.setBoxList(boxList);
                                billMaterialList.add(billMaterial);
                                if (id.equals(_inventoryId)) {
                                    needCount = addAllocationAndOutStock(needCount, invDetail, materialData, invDataMap, materialDetailMap, outStockBoxNoList, allocateNo, stockNo, intWarehouseCode, _inventoryId, invDetailCount, boxNo, locationNo, rfid);
                                }
                            }

                        }
                        if (needCount <= 0) {
                            break;
                        }
                    }
                    //出库
                    List<String> boxNoList = new ArrayList<>();
                    List<VtuzxMap> bcBoxList = new ArrayList<>();
                    for (VtuzxMap outStockBoxNo : outStockBoxNoList) {
                        String boxNo = VtuzxUtil.getString(outStockBoxNo, "boxNo");
                        String stockNo = VtuzxUtil.getString(outStockBoxNo,"stockNo");
                        if (VtuzxUtil.getBoolean(outStockBoxNo, "isAllOut")) {
                            boxNoList.add(boxNo);
                        } else {
                            bcBoxList.add(new VtuzxMap("boxNo", boxNo)
                                    .append("count", BigDecimal.valueOf(VtuzxUtil.getDouble(outStockBoxNo, "outCount")).setScale(2, RoundingMode.HALF_UP).doubleValue())
                                    .append("locationNo", VtuzxUtil.getString(outStockBoxNo, "locationNo")));
                        }
                        try {
                            coreInventoryService.reduceInventory(null, "batch", BillEvent.Audit, BillType.DBCK, stockNo, allocateNo, boxNoList, bcBoxList);
                        } catch (VtuzxException e) {
                            e.printStackTrace();
                        }

                    }
                }
                //在做入库
                try {
                    coreInventoryService.addInventory(null,"batch",BillEvent.Audit,BillType.CGRK,"CK002",allocateNo,billMaterialList);
                } catch (VtuzxException e){
                    _logger.info(e.getMessage());
                }


                if (traceCodeList.size() != 0) {//唯一码出入库
                    List<Document> traceBoxDataList = new ArrayList<>();
                    Iterator<Document> inventoryDetailItr = inventoryDetailDao.findList(Criteria.where("boxNo").in(getBoxNoList), null, 0, 0);
                    while (inventoryDetailItr.hasNext()) {
                        Document inventoryDetailDoc = inventoryDetailItr.next();
                        traceBoxDataList.add(inventoryDetailDoc);
                    }
                    List<ObjectId> invIdList = new ArrayList<>();
                    VtuzxMap detailTraceBackMap = new VtuzxMap(); //key 追溯码，value id
                    for (String traceCode : traceCodeList) {
                        for (Document traceBoxData : traceBoxDataList) {
                            ObjectId detailId = VtuzxUtil.getObject(traceBoxData, "_inventoryId");
                            String boxNo = VtuzxUtil.getString(traceBoxData, "boxNo");
                            String rfid = VtuzxUtil.getString(traceBoxData, "rfid");
                            invIdList.add(detailId);
                            List<Document> traceBack = VtuzxUtil.getObject(traceBoxData, "traceBack");
                            for (Document traceBackForCode : traceBack) {
                                String traceBackNo = VtuzxUtil.getString(traceBackForCode, "traceBackNo");
                                String status = VtuzxUtil.getString(traceBackForCode, "status");
                                if (traceCode.equals(traceBackNo) && "in".equals(status)) {
                                    detailTraceBackMap.append(traceCode, new Document("detailId", detailId.toString()).append("boxNo", boxNo).append("rfid", rfid));
                                    break;
                                }
                            }
                        }
                    }

                    List<Document> inventoryList = new ArrayList<>();
                    List<String> invMaterialList = new ArrayList<>();
                    Iterator<Document> inventoryItr = inventoryDao.findList(Criteria.where("_id").in(invIdList).and("count").gt(0), null, 0, 0);
                    while (inventoryItr.hasNext()) {
                        Document inventoryDoc = inventoryItr.next();
                        String materialNo = VtuzxUtil.getString(inventoryDoc, "materialNo");
                        invMaterialList.add(materialNo);
                        inventoryList.add(inventoryDoc);
                    }
                    VtuzxMap materialInvDataDoc = new VtuzxMap();
                    Iterator<Document> materialInvItr = materialDao.findList(Criteria.where("fNumber").in(invMaterialList), null, 0, 0);
                    while (materialInvItr.hasNext()) {
                        Document materialInvDoc = materialInvItr.next();
                        String fNumber = VtuzxUtil.getString(materialInvDoc, "fNumber");
                        materialInvDataDoc.append(fNumber, materialInvDoc);
                    }

                    List<BillMaterial> zsBillMaterialList = new ArrayList<>();//带追溯入库
                    for (Document inventory : inventoryList) {
                        String id = VtuzxUtil.getString(inventory, "_id");
                        String materialNo = VtuzxUtil.getString(inventory, "materialNo");
                        Document materialDataMap = VtuzxUtil.getObject(materialInvDataDoc, materialNo);
                        String materialName = VtuzxUtil.getString(materialDataMap, "fName");
                        String materialSpec = VtuzxUtil.getString(materialDataMap, "fSpecification");
                        String unit = VtuzxUtil.getString(materialDataMap, "fBaseUnitIdFName");
                        String batchNo = VtuzxUtil.getString(inventory, "batchNo");
                        int exp = VtuzxUtil.getInt(inventory,"exp");

                        BillMaterial billMaterial = new BillMaterial();
                        billMaterial.setMaterialNo(materialNo);
                        billMaterial.setUnit(unit);
                        billMaterial.setBatchNo(batchNo);
                        billMaterial.setProduceDate(VtuzxUtil.formatYmdHmsF(new Date()));
                        billMaterial.setExp(exp);
                        List<BillMaterialBox> boxList = new ArrayList<>();
                        List<Document> traceBackList = new ArrayList<>();
                        BillMaterialBox box = new BillMaterialBox();
                        box.getBoxNo();
                        box.setBoxNo("A02" +  new Date().getTime());
                        for (VtuzxMap map : materialSerialList){
                            String goodsNo = VtuzxUtil.getString(map,"goodsNo");
                            if (materialNo.equals(goodsNo)){
                                String traceBackNo = VtuzxUtil.getString(map,"traceBackNo");
                                Document traceBack = new Document("traceBackNo",traceBackNo)
                                        .append("status","in");
                                traceBackList.add(traceBack);
                            }
                        }
                        box.setCount(traceBackList.size());
                        box.setLocationNo("FH001");
                        box.setTraceBack(traceBackList);
                        box.setIsTaskIn(true);
                        boxList.add(box);

                        for (Map.Entry entry : detailTraceBackMap.entrySet()){
                            Document detailDoc = (Document) entry.getValue();
                            String detailId = VtuzxUtil.getString(detailDoc, "detailId");
                            String boxNo = VtuzxUtil.getString(detailDoc, "boxNo");
                            String rfid = VtuzxUtil.getString(detailDoc, "rfid");
                            if (id.equals(detailId)) {
                                ObjectId _detailId = VtuzxUtil.getObject(materialDetailMap, allocateNo + materialNo + batchNo);
                                if (!VtuzxUtil.isEmpty(_detailId)) {
                                    allocationDetailDao.updateByIdRedirect(_detailId, new Document("$inc", new Document("boxCount", 1).append("count", 1)));
                                    Document detailBox = new Document();
                                    detailBox.append("billNo", allocateNo);
                                    detailBox.append("_detailId", _detailId);
                                    detailBox.append("materialNo", materialNo);
                                    detailBox.append("materialName", materialName);
                                    detailBox.append("materialSpec", materialSpec);
                                    detailBox.append("boxNo", boxNo);
                                    detailBox.append("batchNo", batchNo);
                                    detailBox.append("stockNo", outWarehouseCode);
                                    detailBox.append("unit", unit);
                                    detailBox.append("rfid", rfid);
                                    detailBox.append("allocationType", "jiKeYun");
                                    detailBox.append("count", 1);
                                    detailBox.append("traceBack", entry.getKey());
                                    allocationDetailBoxDao.insertOne(detailBox);

                                } else {
                                    Criteria detailCond = new Criteria();
                                    detailCond.and("billNo").is(allocateNo);
                                    detailCond.and("materialNo").is(materialNo);
                                    detailCond.and("batchNo").is(batchNo);
                                    detailCond.and("stockNo").is(outWarehouseCode);

                                    Document detail = allocationDetailDao.findOne(detailCond);
                                    Document updateVal = new Document();
                                    if (detail == null) {
                                        updateVal.append("billNo", allocateNo);
                                        updateVal.append("stockNo", outWarehouseCode);
                                        updateVal.append("materialNo", materialNo);
                                        updateVal.append("materialName", materialName);
                                        updateVal.append("materialSpec", materialSpec);
                                        updateVal.append("batchNo", batchNo);
                                        updateVal.append("unit", unit);
                                        updateVal.append("boxCount", 1);
                                        updateVal.append("count", 1);
                                        updateVal.append("allocationType", "jiKeYun");
                                        updateVal.append("toStockNo", intWarehouseCode);

                                    } else {
                                        updateVal = new Document("$inc", new Document("boxCount", 1).append("count", 1));
                                    }
                                    if (detail == null) {
                                        _detailId = allocationDetailDao.insertOne(updateVal);
                                    } else {
                                        _detailId = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
                                        allocationDetailDao.updateByIdRedirect(_detailId, updateVal);
                                    }
                                    Document detailBox = new Document();
                                    detailBox.append("billNo", allocateNo);
                                    detailBox.append("_detailId", _detailId);
                                    detailBox.append("materialNo", materialNo);
                                    detailBox.append("materialName", materialName);
                                    detailBox.append("materialSpec", materialSpec);
                                    detailBox.append("boxNo", boxNo);
                                    detailBox.append("batchNo", batchNo);
                                    detailBox.append("stockNo", outWarehouseCode);
                                    detailBox.append("unit", unit);
                                    detailBox.append("rfid", rfid);
                                    detailBox.append("allocationType", "jiKeYun");
                                    detailBox.append("count", 1);
                                    detailBox.append("traceBack", entry.getKey());
                                    allocationDetailBoxDao.insertOne(detailBox);
                                }
                            }
                        }
                        billMaterial.setBoxList(boxList);
                        zsBillMaterialList.add(billMaterial);
                    }
                    coreInventoryService.reduceInventory(null, "batch", BillEvent.Audit, BillType.DBCK, outWarehouseCode, allocateNo, null, null, zsBoxList);
                    //做入库
                    try {
                        coreInventoryService.addInventory(null,"batch",BillEvent.Audit,BillType.CGRK,"CK002",allocateNo,zsBillMaterialList);
                    } catch (VtuzxException e){
                        _logger.info(e.getMessage());
                    }
                }

                double sumCount = 0d;
                int sumBoxCount = 0;
                Iterator<Document> allocationDetailItr = allocationDetailDao.findList(Criteria.where("billNo").is(allocateNo), null, 0, 0);
                while (allocationDetailItr.hasNext()) {
                    Document allocationDetailDoc = allocationDetailItr.next();
                    double count = VtuzxUtil.getDouble(allocationDetailDoc, "count");
                    int boxCount = VtuzxUtil.getInt(allocationDetailDoc, "boxCount");
                    sumCount += count;
                    sumBoxCount += boxCount;
                }

                Document allDoc = new Document("billNo", allocateNo)
                        .append("stockNo", intWarehouseCode)
                        .append("allocationType", "jiKeYun")
                        .append("toStockNo", "CK002")
                        .append("status", "audit")
                        .append("count", sumCount)
                        .append("boxCount", sumBoxCount)
                        .append("auditTime", new Date())
                        .append("auditUserName", "吉克云调拨单定时同步")
                        .append("_auditUserId", null)
                        .append("createUserName", "吉克云调拨单定时同步")
                        .append("_createUserId", null);
                allocationDao.insertOne(allDoc);
            }
        }
        syncAllocation(from, to, pageIndex + 1);
    }

    private double addAllocationAndOutStock(double needCount, Document invDetail, VtuzxMap materialData, VtuzxMap invDataMap, VtuzxMap materialDetailMap, List<VtuzxMap> outStockBoxNoList, String allocateNo, String outWarehouseCode, String intWarehouseCode,
                                            String inventoryId, double invDetailCount, String boxNo, String locationNo, String rfid) {

        VtuzxMap outStockBoxNoMap = new VtuzxMap();
        Document allocationDoc = VtuzxUtil.getObject(invDataMap, inventoryId);
        String materialNo = VtuzxUtil.getString(allocationDoc, "materialNo");
        Document materialDataMap = VtuzxUtil.getObject(materialData, materialNo);
        String materialName = VtuzxUtil.getString(materialDataMap, "fName");
        String materialSpec = VtuzxUtil.getString(materialDataMap, "fSpecification");
        String unit = VtuzxUtil.getString(materialDataMap, "fBaseUnitIdFName");
        String batchNo = VtuzxUtil.getString(allocationDoc, "batchNo");
        Criteria detailCond = Criteria.where("stockNo").is(outWarehouseCode);
        detailCond.and("billNo").is(allocateNo);
        detailCond.and("materialNo").is(materialNo);
        detailCond.and("batchNo").is(batchNo);
        detailCond.and("allocationType").is("jiKeYun");
        Document detail = allocationDetailDao.findOne(detailCond);
        Document updateVal = new Document();

        if (detail == null) {
            updateVal.append("billNo", allocateNo);
            updateVal.append("stockNo", outWarehouseCode);
            updateVal.append("materialNo", materialNo);
            updateVal.append("materialName", materialName);
            updateVal.append("materialSpec", materialSpec);
            updateVal.append("batchNo", batchNo);
            updateVal.append("unit", unit);
            updateVal.append("boxCount", 1);
            updateVal.append("allocationType", "jiKeYun");
            updateVal.append("toStockNo", "CK002");
            if (needCount - invDetailCount > 0) { //没达到所需数量，这个箱子在列表数据里标记删除，所需数量修改成剩余数量
                updateVal.append("count", invDetailCount);
                invDetail.append("isDelete", true);
                outStockBoxNoMap.append("boxNo", boxNo).append("count", invDetailCount).append("outCount", invDetailCount).append("isAllOut", true).append("locationNo", locationNo).append("stockNo",outWarehouseCode);
            } else {
                updateVal.append("count", needCount);
                invDetail.append("count", invDetailCount - needCount);
                outStockBoxNoMap.append("boxNo", boxNo).append("count", invDetailCount).append("outCount", needCount).append("isAllOut", false).append("locationNo", locationNo).append("stockNo",outWarehouseCode);
            }
            outStockBoxNoList.add(outStockBoxNoMap);
        }
        ObjectId _detailId;
        if (detail == null) {
            _detailId = allocationDetailDao.insertOne(updateVal);
        } else {
            _detailId = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
            allocationDetailDao.updateByIdRedirect(_detailId, updateVal);
        }

        String key = allocateNo + materialNo + batchNo;
        materialDetailMap.append(key, _detailId);

        Document detailBox = new Document();
        detailBox.append("billNo", allocateNo);
        detailBox.append("_detailId", _detailId);
        detailBox.append("materialNo", materialNo);
        detailBox.append("materialName", materialName);
        detailBox.append("materialSpec", materialSpec);
        detailBox.append("boxNo", boxNo);
        detailBox.append("batchNo", batchNo);
        detailBox.append("stockNo", outWarehouseCode);
        detailBox.append("unit", unit);
        detailBox.append("rfid", rfid);
        detailBox.append("allocationType", "jiKeYun");
        if (needCount - invDetailCount > 0) {
            detailBox.append("count", invDetailCount);
            needCount = (needCount - invDetailCount);
        } else {
            detailBox.append("count", needCount);
            needCount = 0;
        }
        allocationDetailBoxDao.insertOne(detailBox);

        return needCount;
    }


    /**
     * 销售单
     * @param from
     * @param to
     * @param pageIndex
     * @throws Exception
     */
    @Override
    public void syncSaleBill(Date from, Date to, int pageIndex) throws Exception {
        _logger.info(String.format("导入%s - %s的销售数据(发货在途)", VtuzxUtil.formatYmdHmsF(from), VtuzxUtil.formatYmdHmsF(to)));
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));

        VtuzxMap saleMap = jiKeYunApiService.getSaleBill(storeDoc,
                new VtuzxMap("startModified", from)//发货时间
                        .append("endModified", to)//发货时间
                        .append("pageSize", 50)
                        .append("tradeStatus",6000)//单据状态发货在途
                        .append("pageIndex", pageIndex)
                        .append("fields", "couponFee,companyName,consignTime,isFit,tradeFrom,goodsSerial.subTradeId," +
                                "goodsSerial.skuId,goodsSerial.serialNo,warehouseName,warehouseCode,customerCode," +
                                "goodsDetail.goodsNo,goodsDetail.shareFavourableAfterFee,goodsDelivery.productionDate,goodsDelivery.expirationDate," +
                                "goodsDelivery.batchNo,tradeNo,tradeStatus,shopName,flagIds,sysFlagIds,flagNames," +
                                "tradeCount,shareFavourableFee,goodsDetail.unit,goodsDetail.goodsName," +
                                "goodsDetail.specName,goodsDetail.sellCount,goodsDetail.sellPrice," +
                                "goodsDetail.taxRate,sellerMemo,gmtCreate,tradeTime,invoiceStatus,departName" +
                                "seller,onlineTradeNo,appendMemo,buyerMemo,otherFee,discountFee,isGift,goodsMemo"));


        System.out.println(pageIndex);
        Map<String, Object> result = VtuzxUtil.getObject(saleMap, "result");
        String tradeString = VtuzxUtil.getString(result,"data");
        if (VtuzxUtil.isEmpty(tradeString)){
            return;
        }
        Map<String,Object> tradeData = JSON.parseObject(tradeString,new TypeReference<HashMap<String,Object>>(){});
        JSONArray jsonArray = VtuzxUtil.getObject(tradeData,"Trades");
        List<String> tradeNoList = new ArrayList<>();//销售单号集合单集合
        List<Document> tradeList = new ArrayList<>();//需要添加到数据库的销售
        for (int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonTrades = (JSONObject) jsonArray.get(i);
            //吉客云的json首字母变成了大写,转成小写
            Map<String,Object> tradeMap = new HashMap<>();
            for (String key : jsonTrades.keySet()){
                String modifyKey = key.substring(0,1).toLowerCase() + key.substring(1);
                tradeMap.put(modifyKey,jsonTrades.get(key));
            }
            String tradeNo = VtuzxUtil.getString(tradeMap,"tradeNo");
            if(!tradeNoList.contains(tradeNo)){
                tradeNoList.add(tradeNo);
            }
//            Document oldSaleDoc = jikeyunSaleDao.findOne(Criteria.where("tradeNo").is(tradeNo));
            Document tradeDoc = new Document(tradeMap);
            //查询仓库金蝶仓库id
            String warehouseName = VtuzxUtil.getString(tradeDoc,"warehouseName");
            String stockId = getStockId(warehouseName, storeDoc);
            tradeDoc.append("stockId",stockId);
            String consignTime = VtuzxUtil.getString(tradeDoc,"ConsignTime");//发货日期
            Date consignDate = VtuzxUtil.parseDate(consignTime);
            tradeDoc.remove("consignTime");
            tradeDoc.append("consignTime",consignDate);

            //通过销售单号查询销售结算单获取客户名称，客户账号，结算时间，原订单金额，结算订单金额等数据
            //吉客云查询结算单无法查询多个
            String colsList = "[\"tradeSettleOrder.settleTime\",\"tradeSettleOrderDetailArr.sellTotal\",\"tradeSettleOrderDetailArr.shareFavourableAfterFee\",\"tradeSettleOrder.payment\",\"tradeSettleOrder.settleFee\",\"settleNo\",\"tradeSettleOrderCustomer.endCustomerAccount\",\"tradeSettleOrderCustomer.customerName\",\"tradeSettleOrderCustomer.customerAccount\"]";

            VtuzxMap settleMap = jiKeYunApiService.getTradeSettleAllInfo(storeDoc,
                    new VtuzxMap()
                            .append("tradeNo",tradeNo)
                            .append("cols",colsList));

            Map<String, Object> settleResult = VtuzxUtil.getObject(settleMap, "result");
            List<Map<String, Object>> settleData = VtuzxUtil.getObject(settleResult, "data");
            String customerName = "";
            if (!VtuzxUtil.isEmpty(settleData)){
                Map<String, Object> settle = settleData.get(0);
                Map<String,Object> tradeSettleOrder = VtuzxUtil.getObject(settle,"tradeSettleOrder");
                double payment = VtuzxUtil.getDouble(tradeSettleOrder,"payment");//原订单金额
                double settleFee = VtuzxUtil.getDouble(tradeSettleOrder,"settleFee");//原订单金额
                String settleTime = VtuzxUtil.getString(tradeSettleOrder,"settleTime");//结算时间
                Map<String,Object> tradeSettleOrderCustomer = VtuzxUtil.getObject(settle,"tradeSettleOrderCustomer");
                customerName = VtuzxUtil.getString(tradeSettleOrderCustomer,"customerName");//客户名称
                String customerAccount = VtuzxUtil.getString(tradeSettleOrderCustomer,"customerAccount");//客户账号
                tradeDoc.append("payment",payment)
                        .append("settleFee",settleFee)
                        .append("settleTime",VtuzxUtil.parseDate(settleTime));

                Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
                Matcher m = p.matcher(customerName);
                if(!m.find() && customerName.length() > 8){//说明是加密的
                    tradeDoc.append("customerName","加密客户")
                            .append("customerAccount","加密账号");
                } else {
                    tradeDoc.append("customerName",customerName)
                            .append("customerAccount",customerAccount);
                }
            }
            tradeList.add(tradeDoc);
        }
        _logger.info("获取到的销售单号(发货在途)" + tradeNoList.toString());

        //删除已有的数据然后添加新的数据
        jikeyunSaleDao.deleteMany(Criteria.where("tradeNo").in(tradeNoList));
        jikeyunSaleDao.insertMany(tradeList);
        for (Document tradeDoc : tradeList){
            int tradeStatus = VtuzxUtil.getInt(tradeDoc, "tradeStatus");//订单状态
            String flagName = VtuzxUtil.getString(tradeDoc, "flagNames"); //标记
            String tradeNo = VtuzxUtil.getString(tradeDoc, "tradeNo"); //销售单号
            String shopName = VtuzxUtil.getString(tradeDoc, "shopName");//店铺名称(销售渠道)
            String warehouseName = VtuzxUtil.getString(tradeDoc,"warehouseName");
            String consignTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(tradeDoc,"consignTime"));
            int tradeFrom = VtuzxUtil.getInt(tradeDoc,"tradeFrom");//订单来源，1网店
            if (!flagName.contains("售后")) {
                if (!flagName.contains("寄存")) {
                    if ((tradeStatus == 9090 || tradeStatus == 6000) && !flagName.contains("补称")) { //订单状态是发货在途、已完成
                        List<Map<String, Object>> goodsSerials = VtuzxUtil.getObject(tradeDoc, "goodsSerials");
                        List<Map<String, Object>> goodsDetail = VtuzxUtil.getObject(tradeDoc, "goodsDetail");
                        List<Map<String, Object>> tradeOrderList = VtuzxUtil.getObject(tradeDoc, "tradeOrderAssemblyGoodsDtoList");//组合装信息

                        if (!VtuzxUtil.isEmpty(goodsSerials)) {
                            for (Map<String, Object> serialData : goodsSerials) {
                                String serialNo = VtuzxUtil.getString(serialData, "SerialNo");
                                if (!VtuzxUtil.isEmpty(serialNo)) {
                                    if (serialNo.startsWith("HTTP://ZS")) {
                                        if (!warehouseName.equals("电商——物流出库仓库") && !"外埠物流仓库".equals(warehouseName)) {//发货仓库非网购仓库填写追溯链信息
                                            StringBuilder sb = new StringBuilder(serialNo.toLowerCase());
                                            sb.setCharAt(49, 'Z');
                                            sb.setCharAt(44, 'C');
                                            String newSerialNo = sb.toString();
                                            Document updateDoc = new Document();
                                            updateDoc.append("saleChnnel", shopName)//销售渠道
                                                    .append("saleTime", consignTime)//发货时间
                                                    .append("lastTime", consignTime)//最后操作时间
                                                    .append("tradeNo", tradeNo);
                                            serialData.replace("serialNo", newSerialNo);
                                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo), updateDoc);
                                            _logger.info(String.format("添加追溯链信息[%s]", serialNo));
//                                            System.out.println("追溯链" + newSerialNo);
                                        }
                                        if ("外埠物流仓库".equals(warehouseName)) {//如果发货仓库是外部物流仓库
                                            String customerCode = VtuzxUtil.getString(tradeDoc, "customerCode");
                                            //从客户列表查询客户名称
                                            VtuzxMap customerMap = jiKeYunApiService.customerList(storeDoc, new VtuzxMap("customerCode", customerCode));
                                            Map<String, Object> customerResult = VtuzxUtil.getObject(customerMap, "result");
                                            List<Map<String, Object>> customerData = VtuzxUtil.getObject(customerResult, "data");
//                                            List<Map<String, Object>> customers = VtuzxUtil.getObject(customerData, "trades");
                                            String customerName = VtuzxUtil.getString(customerData.get(0), "nickname");
                                            StringBuilder sb = new StringBuilder(serialNo.toLowerCase());
                                            sb.setCharAt(49, 'Z');
                                            sb.setCharAt(44, 'C');
                                            String newSerialNo = sb.toString();
                                            Document updateDoc = new Document();
                                            updateDoc.append("saleChnnel", customerName)//销售渠道
                                                    .append("saleTime", consignTime)//发货时间
                                                    .append("lastTime", consignTime)//最后操作时间
                                                    .append("tradeNo", tradeNo);
                                            serialData.replace("serialNo", newSerialNo);
                                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo), updateDoc);
                                            _logger.info(String.format("添加追溯链信息[%s]", serialNo));
//                                            System.out.println("追溯链" + newSerialNo);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }




        syncSaleBill(from,to,pageIndex + 1);
    }

    /* 中台出库 */
    private void outStock(List<Map<String, Object>> goodsDetail, String tradeNo, String beforeStockNo, List<String> traceBackList, VtuzxMap serialAndGoodsMap, VtuzxMap materialMap) throws VtuzxException {
        String billNo = IXqcConst.createBillNo(BillType.XSCK);
        VtuzxMap sysParamMap = getParameters(new VtuzxMap("keys", new VtuzxArrayList<>("traceabilityCodeUrl")));
        VtuzxMap traceabilityCodeUrlMap = VtuzxUtil.getObject(sysParamMap, "traceabilityCodeUrl");
        if (traceabilityCodeUrlMap == null) {
            throw new VtuzxException(IXqcConst.Msg_E_system);
        }
        String value = VtuzxUtil.getString(traceabilityCodeUrlMap, "value");
        List<Document> zsBoxList = new ArrayList<>();
//        List<String> traceBackList = new ArrayList<>();
//        if (!VtuzxUtil.isEmpty(goodsSerial)) {
//            for (Map<String, Object> goodsSerialMap: goodsSerial) {
//                String serialNo = VtuzxUtil.getString(goodsSerialMap, "serialNo");
//                if (serialNo.startsWith("http")) {
//                    traceBackList.add(serialNo);
//                } else {
//                    traceBackList.add(value + "?traceabilityCode=" + serialNo);
//                }
//            }
//        }
        // 先找到总共物料对应数量 减去每个物料需要扣去追溯码的 剩下的就是需要物料出库的
        VtuzxMap materialCountMap = new VtuzxMap(); //需要出库的物料和数量
        List<String> materialNoList = new ArrayList<>();
        List<ObjectId> allIdList = new ArrayList<>();
        VtuzxMap allMaterialCountMap = new VtuzxMap();
        for (Map<String, Object> goodsDetailMap: goodsDetail) {
            String goodsNo = VtuzxUtil.getString(goodsDetailMap, "goodsNo");
            double sellCount = VtuzxUtil.getDouble(goodsDetailMap, "sellCount");
            List<String> serialList = VtuzxUtil.getObject(serialAndGoodsMap, goodsNo);
            double count = 0d;
            if (!VtuzxUtil.isEmpty(serialList)) {
                count = sellCount - serialList.size();
            } else {
                count = sellCount;
            }
            if (count > 0) {
                materialNoList.add(goodsNo);
                double outCount = VtuzxUtil.getDouble(materialCountMap, goodsNo);
                if (!VtuzxUtil.isEmpty(serialList)) {
                    materialCountMap.append(goodsNo, outCount + (sellCount - serialList.size()));
                } else {
                    materialCountMap.append(goodsNo, outCount + sellCount);
                }
            }
            goodsDetailMap.put("sellCount", count);
        }


        List<String> getBoxNoList = new ArrayList<>();
        Iterator<Document> traceabilityCodeDetailItr = traceabilityCodeDetailDao.findList(Criteria.where("traceabilityCode").in(traceBackList), null, 0, 0);
        while (traceabilityCodeDetailItr.hasNext()) {
            Document traceabilityCodeDetailDoc = traceabilityCodeDetailItr.next();
            String boxNo = VtuzxUtil.getString(traceabilityCodeDetailDoc, "boxNo");
            getBoxNoList.add(boxNo);
        }

        List<ObjectId> invTraceBackIdList = new ArrayList<>();
        Iterator<Document> inventoryDetailItr = inventoryDetailDao.findList(Criteria.where("boxNo").in(getBoxNoList).and("status").is("in"), null, 0, 0);
        while (inventoryDetailItr.hasNext()) {
            Document inventoryDetailDoc = inventoryDetailItr.next();
            List<Document> traceBack = VtuzxUtil.getObject(inventoryDetailDoc, "traceBack");
            String boxNo = VtuzxUtil.getString(inventoryDetailDoc, "boxNo");
            invTraceBackIdList.add(VtuzxUtil.getObject(inventoryDetailDoc, "_inventoryId"));
            for (Document traceBackDoc: traceBack) {
                String traceBackNo = VtuzxUtil.getString(traceBackDoc, "traceBackNo");
                String status = VtuzxUtil.getString(traceBackDoc, "status");
                if (traceBackList.contains(traceBackNo) && "in".equals(status)) {
                    Document zsBoxDoc = new Document();
                    zsBoxDoc.append("boxNo", boxNo).append("traceBack", traceBackNo);
                    zsBoxList.add(zsBoxDoc);
                }
            }
        }
        //按追溯码出库
        if (zsBoxList.size() != 0) {
            coreInventoryService.reduceInventory(null, "吉克云自动同步", BillEvent.Audit, BillType.XSCK, beforeStockNo, billNo, null, null, zsBoxList);
        }

        List<Document> invDocList = new ArrayList<>();
        VtuzxMap invDataMap = new VtuzxMap();
        Iterator<Document> invItr = inventoryDao.findList(Criteria.where("materialNo").in(materialNoList).and("stockNo").is(beforeStockNo).and("count").gt(0), null, 0, 0);
        while (invItr.hasNext()) {
            Document invDoc = invItr.next();
            String id = VtuzxUtil.getString(invDoc, "_id");
            invDataMap.append(id, invDoc);
            invDocList.add(invDoc);
        }

        materialCountMap.forEach((k, v) -> {
            for (Document invDoc : invDocList) {
                boolean isDelete = VtuzxUtil.getBoolean(invDoc, "isDelete");
                if (!isDelete) {
                    ObjectId id = VtuzxUtil.getObject(invDoc, "_id");
                    String materialNo = VtuzxUtil.getString(invDoc, "materialNo");
                    double count = VtuzxUtil.getDouble(invDoc, "count");
                    double jiKeYunCount = VtuzxUtil.getDouble(materialCountMap, materialNo);
                    if (jiKeYunCount > count) { //即时库存分录数量全部出库
                        materialCountMap.append(materialNo, jiKeYunCount - count); //吉克云还有多少需要出库
                        allMaterialCountMap.append(id.toString(), count); //这条全部出库
                        invDoc.append("isDelete", true);
                        allIdList.add(id);
                    } else { //即时库存分录部分数量出库
                        allMaterialCountMap.append(id.toString(), jiKeYunCount);
                        invDoc.append("count", count - jiKeYunCount);
                        allIdList.add(id);
                        break;
                    }
                }
            }
        });

        List<Document> invDetailList = new ArrayList<>();
        Criteria cond = new Criteria();
        cond.orOperator(Criteria.where("boxNo").in(getBoxNoList), Criteria.where("_inventoryId").in(allIdList).and("status").is("in"));
        Iterator<Document> invDetailItr = inventoryDetailDao.findList(cond, null, 0, 0);
        while (invDetailItr.hasNext()) {
            Document invDetailDoc = invDetailItr.next();
            invDetailList.add(invDetailDoc);
        }
        VtuzxMap materialDetailMap = new VtuzxMap();
        allMaterialCountMap.forEach((k, v) -> { //k:id , v:这个id所需的数量
            List<VtuzxMap> outStockBoxNoList = new ArrayList<>();
            double needCount = (double) v;
            for (Document invDetail : invDetailList) {
                if (!VtuzxUtil.getBoolean(invDetail, "isDelete")) {
                    String inventoryId = VtuzxUtil.getString(invDetail, "_inventoryId");
                    double invDetailCount = VtuzxUtil.getDouble(invDetail, "count");
                    String boxNo = VtuzxUtil.getString(invDetail, "boxNo");
                    String locationNo = VtuzxUtil.getString(invDetail, "locationNo");
                    String rfid = VtuzxUtil.getString(invDetail, "rfid");
                    if (k.equals(inventoryId)) {
                        //存个历史
                    }
                }
                if (needCount <= 0) {
                    break;
                }
            }
            //出库
            List<String> boxNoList = new ArrayList<>();
            List<VtuzxMap> bcBoxList = new ArrayList<>();
            for (VtuzxMap outStockBoxNo : outStockBoxNoList) {
                String boxNo = VtuzxUtil.getString(outStockBoxNo, "boxNo");
                if (VtuzxUtil.getBoolean(outStockBoxNo, "isAllOut")) {
                    boxNoList.add(boxNo);
                } else {
                    bcBoxList.add(new VtuzxMap("boxNo", boxNo)
                            .append("count", BigDecimal.valueOf(VtuzxUtil.getDouble(outStockBoxNo, "outCount")).setScale(2, RoundingMode.HALF_UP).doubleValue())
                            .append("locationNo", VtuzxUtil.getString(outStockBoxNo, "locationNo")));
                }
                try {
                    //按箱号出库
                    coreInventoryService.reduceInventory(null, "batch", BillEvent.Audit, BillType.DBCK, beforeStockNo, billNo, boxNoList, bcBoxList);
                } catch (VtuzxException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //传中台订单
    private void createBill(Map<String, Object> trade, List<VtuzxMap> dataList, String org, List<String> billType, VtuzxMap serialAndGoodsMap) {
        String stockNo = VtuzxUtil.getString(trade, "warehouseCode");//仓库编码
        String billNo = VtuzxUtil.getString(trade, "tradeNo");//单号
        double sumCount = 0d;
        int sumBoxCount = 0;
        VtuzxMap idMaterialMap = new VtuzxMap();
        for (VtuzxMap data : dataList) {
            String materialNo = VtuzxUtil.getString(data, "materialNo");
            String materialName = VtuzxUtil.getString(data, "materialName");
            String materialSpec = VtuzxUtil.getString(data, "materialSpec");
            String batchNo = VtuzxUtil.getString(data, "batchNo");
            String unit = VtuzxUtil.getString(data, "unit");
            double count = VtuzxUtil.getDouble(data, "count");
            sumCount += count;
            sumBoxCount++;
            Criteria detailCond = new Criteria("billNo").is(billNo);
            detailCond.and("stockNo").is(stockNo);
            detailCond.and("materialNo").is(materialNo);
            detailCond.and("batchNo").is(batchNo);
            detailCond.and("unit").is(unit);
            detailCond.and("type").is("jiKeYun");
            Document detail = saleOutDetailDao.findOne(detailCond);
            Document updateVal = new Document();

            if (detail == null) {
                updateVal.append("billNo", billNo);
                updateVal.append("stockNo", stockNo);
                updateVal.append("materialNo", materialNo);
                updateVal.append("materialName", materialName);
                updateVal.append("materialSpec", materialSpec);
                updateVal.append("batchNo", batchNo);
                updateVal.append("unit", unit);
                updateVal.append("_createUserId", null);
                updateVal.append("createUserName", "吉克云单据");
                updateVal.append("boxCount", 1);
                updateVal.append("count", count);
                updateVal.append("inStockTime", VtuzxUtil.formatYmdHmsF(new Date()));
                updateVal.append("type", "jiKeYun");
                updateVal.append("org", org);
                updateVal.append("billType", billType);
            } else {
                updateVal = new Document("$inc", new Document("boxCount", 1).append("count", count));
            }
            if (detail == null) {
                ObjectId _detailId = saleOutDetailDao.insertOne(updateVal);
                idMaterialMap.append(materialNo, _detailId);
            } else {
                String _detailId = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
                saleOutDetailDao.updateByIdRedirect(_detailId, updateVal);
            }
        }

        serialAndGoodsMap.forEach((k, v) -> {
            List<String> serList = (List<String>) v;
            ObjectId _detailId = VtuzxUtil.getObject(idMaterialMap, k);
            Document detailBoxDoc = new Document();
            detailBoxDoc.append("_detailId", _detailId);
            detailBoxDoc.append("traceBack", serList);
            detailBoxDoc.append("materialNo", k);
            detailBoxDoc.append("count", serList.size());
            detailBoxDoc.append("billNo", billNo);
            detailBoxDoc.append("stockNo", stockNo);
        });

        Document saleOutDoc = new Document();
        saleOutDoc.append("billNo", billNo);
        saleOutDoc.append("stockNo", stockNo);
        saleOutDoc.append("createUserName", "吉克云单据");
        saleOutDoc.append("status", "audit");
        saleOutDoc.append("count", sumCount);
        saleOutDoc.append("boxCount", sumBoxCount);
        saleOutDoc.append("org", org);
        saleOutDoc.append("billType", billType);
        saleOutDoc.append("createTime",VtuzxUtil.formatYmdHmsF(new Date()));
        saleOutDoc.append("type","jikeyun");
        saleOutDao.insertOne(saleOutDoc);
    }


    private void innerGetTradeSettleAllInfo(Document storeDoc, String tradeNoStr, int pageIndex, VtuzxMap tradeMap) throws Exception {
        VtuzxMap innerGetTradeSettleAllInfoMap = jiKeYunApiService.getTradeSettleAllInfo(storeDoc,
                new VtuzxMap("tradeNo", tradeNoStr)
                        .append("pageSize", 50)
                        .append("pageIndex", pageIndex)
                        .append("cols", "tradeSettleOrderCustomer.settleUnit")
                        .append("detailCols", "tradeNo"));
        Map<String, Object> tradeResult = VtuzxUtil.getObject(innerGetTradeSettleAllInfoMap, "result");
        List<Map<String,Object>> tradeData = VtuzxUtil.getObject(tradeResult, "data");
        if (tradeData != null && tradeData.size() > 0){
            List<Map<String, Object>> tradeSettleOrderDetailArr = VtuzxUtil.getObject(tradeData.get(0), "tradeSettleOrderDetailArr");
            if (tradeSettleOrderDetailArr.size() > 0) {
                for (Map<String, Object> tradeSettleOrderDetail : tradeSettleOrderDetailArr) {
                    String tradeNo = VtuzxUtil.getString(tradeSettleOrderDetail, "tradeNo");
                    String settleUnit = VtuzxUtil.getString(tradeSettleOrderDetail, "tradeSettleOrderCustomer.settleUnit");
                    tradeMap.append(tradeNo, settleUnit);
                }
                pageIndex++;
                innerGetTradeSettleAllInfo(storeDoc, tradeNoStr, pageIndex, tradeMap);
            }
        }
    }

    private void innerGetSaleData(Document storeDoc, String shopCode, VtuzxMap saleMap) throws Exception {
        VtuzxMap getSales = jiKeYunApiService.getSales(storeDoc,
                new VtuzxMap("code", shopCode)
                        .append("pageSize", 50)
                        .append("pageIndex", 0));
        Map<String, Object> result = VtuzxUtil.getObject(getSales, "result");
        Map<String, Object> data = VtuzxUtil.getObject(result, "data");
        List<Map<String, Object>> salesChannelInfo = VtuzxUtil.getObject(data, "salesChannelInfo");
        for (Map<String, Object> salesChannel : salesChannelInfo) {
            String companyName = VtuzxUtil.getString(salesChannel, "companyName");
            saleMap.append(shopCode, companyName);
        }
    }


    /**
     * 同步极客云收款单并传到金蝶(判断是不是预收款)
     *
     * @param from
     * @param to
     * @param pageIndex
     */
    @Override
    public void syncCollection(Date from, Date to, int pageIndex) throws Exception {
        //先从极客云同步收款单
        //收款单参数
        VtuzxMap param = new VtuzxMap();
        param.append("startBillDate", VtuzxUtil.formatYmdHmsF(from))
                .append("endBillDate", VtuzxUtil.formatYmdHmsF(to))
                .append("billType", "11")
                .append("status", "3")//单据状态已审核
//                .append("companyId", "1685388588149735936")//公司id只查询野象公司的
                .append("pageSize", 50)
                .append("pageIndex", pageIndex);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap payAndCol = jiKeYunApiService.getPayAndCol(storeDoc, param);
        Map<String, Object> result = VtuzxUtil.getObject(payAndCol, "result");
        List<Map<String, Object>> data = VtuzxUtil.getObject(result, "data");
        if (data.size() <= 0) {
            return;
        }
        List<String> billNumList = new ArrayList<>();
        List<Document> billList = new ArrayList<>();
        //往中台添加数据
        for (Map<String, Object> map : data) {
            Document colDao = new Document(map);
//            List<Map<String,Object>> billTransDetailList = VtuzxUtil.getObject(colDao,"billTransDetailList");
//            String bankAccountName = VtuzxUtil.getString(billTransDetailList.get(0),"bankAccountName");//账户类型
//            colDao.append("bankAccountName",bankAccountName);
            String billNum = VtuzxUtil.getString(colDao,"billNum");
//            Document oldColDoc = collectionDao.findOne(Criteria.where("billNum").is(billNum));
            if (!billNumList.contains(billNum)){
                billNumList.add(billNum);
            }
            billList.add(colDao);
        }
        collectionDao.deleteMany(Criteria.where("billNum").in(billNumList));
        collectionDao.insertMany(billList);
        syncCollection(from, to, pageIndex + 1);
    }

    /**
     * 同步吉克云付款单并传到金蝶收款退款单
     *
     * @param from
     * @param to
     * @param pageIndex
     */
    @Override
    public void syncPayment(Date from, Date to, int pageIndex) throws Exception {
        //先从极客云同步付款单
        //收款单参数
        VtuzxMap param = new VtuzxMap();
        param.append("startBillDate", VtuzxUtil.formatYmdHmsF(from))
                .append("endBillDate", VtuzxUtil.formatYmdHmsF(to))
                .append("billType", "12")//单据类型(12:付款单)
                .append("status", "3")//单据状态已审核
//                .append("companyId", "1685388588149735936")//公司id只查询野象公司的
                .append("pageSize", 50)
                .append("pageIndex", pageIndex);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap payAndCol = jiKeYunApiService.getPayAndCol(storeDoc, param);
        Map<String, Object> result = VtuzxUtil.getObject(payAndCol, "result");
        List<Map<String, Object>> data = VtuzxUtil.getObject(result, "data");
        if (data.size() <= 0) {
            return;
        }

        List<String> billNumList = new ArrayList<>();
        List<Document> billList = new ArrayList<>();
        //往中台添加数据
        for (Map<String, Object> map : data) {
            Document colDao = new Document(map);
            String billNum = VtuzxUtil.getString(colDao,"billNum");
            if (!billNumList.contains(billNum)){
                billNumList.add(billNum);
            }
            billList.add(colDao);

        }
        paymentDao.deleteMany(Criteria.where("billNum").in(billNumList));
        paymentDao.insertMany(billList);

        syncPayment(from, to, pageIndex + 1);
    }

    /**
     * 同步极客云公司间结算(调拨类型)
     *
     * @param from
     * @param to
     * @param pageIndex
     * @throws Exception
     */
    @Override
    public void syncInnerOrder(Date from, Date to, int pageIndex) throws Exception {
        //查询极客云公司间结算单(调拨)
        VtuzxMap param = new VtuzxMap();
        param.append("startGmtCreate", VtuzxUtil.formatYmdHmsF(from))
                .append("endGmtCreate", VtuzxUtil.formatYmdHmsF(to))
//        param.append("orderNos","IS202310226352")
                .append("orderType", 1)//单据类型跨公司调拨
                .append("pageSize", 50)
                .append("pageIndex", pageIndex);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap innerOrderDoc = jiKeYunApiService.getInnerOrder(storeDoc, param);
        Map<String, Object> result = VtuzxUtil.getObject(innerOrderDoc, "result");
        List<Map<String, Object>> data = VtuzxUtil.getObject(result, "data");
        if (data.size() <= 0) {
            return;
        }
        List<String> orderNoList = new ArrayList<>();
        List<Document> orderList = new ArrayList<>();
        for (Map<String, Object> map : data) {
            //先判断结算状态
            int settStatus = VtuzxUtil.getInt(map, "settStatus");
            String orderNo = VtuzxUtil.getString(map, "orderNo");//结算单号
            if (settStatus == 1) {//状态已审核
                if (!orderNoList.contains(orderNo)){
                    orderNoList.add(orderNo);
                }
                Document innerDoc = new Document(map);
                String outCompanyName = VtuzxUtil.getString(innerDoc, "outCompanyName");//应收公司
                //查询仓库id,应收公司是晓芹通过接收方查询仓库id,应收是野象通过发送方查询仓库id
                String stockName = "";
                if (outCompanyName.contains("晓芹")){
                    stockName = VtuzxUtil.getString(innerDoc,"inReldataName");
                } else if (outCompanyName.contains("野象")){
                    stockName = VtuzxUtil.getString(innerDoc,"outReldataName");
                }
                String stockId = getStockId(stockName, storeDoc);
                innerDoc.append("stockId",stockId);
                innerDoc.append("isUpload","no");
                orderList.add(innerDoc);

            }
        }
        //查询公司间结算货品信息表获取到数量,判断是正数还是负数
        int size = orderNoList.toString().indexOf("]");
        String substring = orderNoList.toString().substring(1, size);
        VtuzxMap goodsParam = new VtuzxMap("orderNos", substring);
        VtuzxMap innerOrderGoods = jiKeYunApiService.getInnerOrderGoods(storeDoc, goodsParam);
        Map<String, Object> goodsResult = VtuzxUtil.getObject(innerOrderGoods, "result");
        List<Map<String, Object>> goodsList = VtuzxUtil.getObject(goodsResult, "data");//调拨货品集合
        Map<String,Object> positiveMap = new HashMap<>();//key结算单号 value:是否是正数
        for (Map<String,Object> goodMap : goodsList){
            String orderNo = VtuzxUtil.getString(goodMap,"orderNo");
            double skuCount = VtuzxUtil.getDouble(goodMap,"skuCount");
            Boolean isPositive = (Boolean) positiveMap.get(orderNo);
            if (!VtuzxUtil.isEmpty(isPositive)){
                continue;
            }
            if (skuCount > 0){
                positiveMap.put(orderNo,true);
            } else {
                positiveMap.put(orderNo,false);
            }

        }
        //循环orderList添加货品数量正负信息
        for (Document order : orderList){
            String orderNo = VtuzxUtil.getString(order,"orderNo");
            boolean isPositive = (Boolean) positiveMap.get(orderNo);
            order.append("isPositive",isPositive);
        }
        //删除已经同步的单据然后重新添加
        innersettorderDao.deleteMany(Criteria.where("orderNo").in(orderNoList));
        innersettorderDao.insertMany(orderList);


        syncInnerOrder(from, to, pageIndex + 1);
    }

    /**
     * 获取仓库id
     * @param outReldataName 接收方/发送方
     *
     * @return
     */
    private String getStockId(String outReldataName, Document storeDoc) throws Exception{
        if("bb044山东路专卖店-野象仓库".equals(outReldataName)){
            outReldataName = "bb045山东路专卖店-野象仓库";
        } else if("电商部物流发货仓".equals(outReldataName)){
            outReldataName = "电商——物流出库仓库";
        } else if ("鸡蛋票、油总仓-野象".equals(outReldataName)){
            outReldataName = "鸡蛋票、油、小米粥总仓-野象";
        }
        String stockId = "";
        if (outReldataName.contains("外埠")){
            stockId = "YXWB01";
        } else {
            //去仓库接口查询部门和仓库
            VtuzxMap stockMap = new VtuzxMap();
            stockMap.append("pageIndex",0).append("pageSize",1).append("name",outReldataName);
            VtuzxMap stock = jiKeYunApiService.getStock(storeDoc, stockMap);
            Map<String,Object> result = VtuzxUtil.getObject(stock,"result");
            Map<String,Object> stockData = VtuzxUtil.getObject(result,"data");
            List<Map<String,Object>> warehouseInfo = VtuzxUtil.getObject(stockData,"warehouseInfo");
            if (warehouseInfo.size() > 0){
                stockId = VtuzxUtil.getString(warehouseInfo.get(0),"warehouseCode");//获取仓库编号
            }


        }
        return stockId;
    }
    @Override
    public void syncInnerOrderSale(Date from, Date to, int pageIndex) throws Exception {
        //查询极客云公司间结算单(销售)
        VtuzxMap param = new VtuzxMap();//公司间结算
        param.append("startGmtCreate", VtuzxUtil.formatYmdHmsF(from))
                .append("endGmtCreate", VtuzxUtil.formatYmdHmsF(to))
                .append("orderType", 2)//单据类型跨公司销售
                .append("pageSize", 50)
                .append("pageIndex", pageIndex);
//        param.append("orderNos","IS202405010006,IS202405010009,IS202405010010,IS202405010007,IS202405010008")
//                .append("orderType",2)
//                .append("pageSize",1)
//                .append("pageIndex",0);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap innerOrderDoc = jiKeYunApiService.getInnerOrder(storeDoc, param);
        Map<String, Object> result = VtuzxUtil.getObject(innerOrderDoc, "result");
        List<Map<String, Object>> data = VtuzxUtil.getObject(result, "data");
        if (data.size() <= 0) {
            return;
        }

        List<String> orderNoList = new ArrayList<>();
        List<Document> orderList = new ArrayList<>();
        for (Map<String, Object> map : data) {
            //先判断结算状态
            int settStatus = VtuzxUtil.getInt(map, "settStatus");
            String orderNo = VtuzxUtil.getString(map, "orderNo");//结算单号
            if (settStatus == 1) {//状态已审核
                if (!orderNoList.contains(orderNo)){
                    orderNoList.add(orderNo);
                }
                Document innerDoc = new Document(map);

                innerDoc.append("isUpload","no");
                orderList.add(innerDoc);

            }
        }
        //查询公司间结算货品信息表获取到数量,判断是正数还是负数
        int size = orderNoList.toString().indexOf("]");
        String substring = orderNoList.toString().substring(1, size);
        VtuzxMap goodsParam = new VtuzxMap("orderNos", substring);
        VtuzxMap innerOrderGoods = jiKeYunApiService.getInnerOrderGoods(storeDoc, goodsParam);
        Map<String, Object> goodsResult = VtuzxUtil.getObject(innerOrderGoods, "result");
        List<Map<String, Object>> goodsList = VtuzxUtil.getObject(goodsResult, "data");//调拨货品集合
        Map<String,Object> positiveMap = new HashMap<>();//key结算单号 value:是否是正数
        for (Map<String,Object> goodMap : goodsList){
            String orderNo = VtuzxUtil.getString(goodMap,"orderNo");
            double skuCount = VtuzxUtil.getDouble(goodMap,"skuCount");
            Boolean isPositive = (Boolean) positiveMap.get(orderNo);
            if (!VtuzxUtil.isEmpty(isPositive)){
                continue;
            }
            if (skuCount > 0){
                positiveMap.put(orderNo,true);
            } else {
                positiveMap.put(orderNo,false);
            }

        }
        //循环orderList添加货品数量正负信息,以及仓库信息
        for (Document order : orderList){
            String orderNo = VtuzxUtil.getString(order,"orderNo");
            boolean isPositive = (Boolean) positiveMap.get(orderNo);
            String outCompanyName = VtuzxUtil.getString(order, "outCompanyName");//应收公司
            //查询仓库id,应收公司是晓芹数量是正数的通过接收方查询仓库id,
            //应收公司是晓芹数量是负数的通过供货方查询仓库id
            // 应收是野象数量是正数的通过供货方查询仓库id
            // 应收是野象数量是负数的通过接收方查询仓库id
            String stockName = "";
            if (outCompanyName.contains("晓芹") ){
                if (isPositive){//正数的
                    stockName = VtuzxUtil.getString(order,"inReldataName");//接收方
                } else {
                    stockName = VtuzxUtil.getString(order,"outReldataName");//供货方
                }

            } else if (outCompanyName.contains("野象")){
                if(isPositive){
                    stockName = VtuzxUtil.getString(order,"outReldataName");
                } else {
                    stockName = VtuzxUtil.getString(order,"inReldataName");
                }

            }
            String stockId = getStockId(stockName, storeDoc);
            order.append("stockId",stockId);
            order.append("isPositive",isPositive);
        }

        //删除已经同步的单据然后重新添加
        innersettorderDao.deleteMany(Criteria.where("orderNo").in(orderNoList));
        innersettorderDao.insertMany(orderList);
        syncInnerOrderSale(from, to, pageIndex + 1);
    }

    /**
     * 同步极客云其它出库单(原因是报废的传金蝶其它出)
     *
     * @param from
     * @param to
     * @param pageIndex
     * @throws Exception
     */
    @Override
    public void getStorageOut(Date from, Date to, int pageIndex) throws Exception {
        //查询极客云公出库单
        VtuzxMap param = new VtuzxMap();
        //需要返回的字段
        String selelctFields = "recId,goodsdocNo,inOutDate," +
                "gmtCreate,inouttypeName,vendCustomerName," +
                "warehouseCode,warehouseName,comment,companyId," +
                "companyName,inOutReason,goodsDocDetailList.recId," +
                "goodsDocDetailList.goodsNo,goodsDocDetailList.goodsName," +
                "goodsDocDetailList.goodsName,goodsDocDetailList.skuId," +
                "goodsDocDetailList.skuName,goodsDocDetailList.skuBarcode," +
                "goodsDocDetailList.unitName,goodsDocDetailList.quantity";
        param.append("startDate", VtuzxUtil.formatYmdHmsF(from))
                .append("endDate", VtuzxUtil.formatYmdHmsF(to))
                .append("pageSize", 50)
                .append("inouttype", 204L)//出库类型其它出库
                .append("selelctFields", selelctFields)
                .append("pageIndex", pageIndex);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap stotrageDoc = jiKeYunApiService.getStorageOut(storeDoc, param);
        Map<String, Object> result = VtuzxUtil.getObject(stotrageDoc, "result");
        List<Map<String, Object>> data = VtuzxUtil.getObject(result, "data");
        if (data.size() <= 0) {
            return;
        }
        //金蝶token
        VtuzxKingdeeCloudClient client = kingdeeService.loginKingdee();
        //原因是报废的传金蝶其它出
        for (Map<String, Object> map : data) {
            String inOutReason = VtuzxUtil.getString(map, "inOutReason");//出库原因
            if (inOutReason.equals("报废")) {
                Document storageDoc = new Document(map);
                Thread.sleep(10);
                String billNo = IXqcConst.createBillNo(BillType.JKYCK);
                storageDoc.append("billNo",billNo)
                        .append("isUpload","no");
                storageOutDao.insertOne(storageDoc);
            }
//            String gmtCreate = VtuzxUtil.getString(map, "gmtCreate");//创建日期
//            String goodsdocNo = VtuzxUtil.getString(map, "goodsdocNo");//出库单号
//            List<Map<String, Object>> goodsDocDetailList = VtuzxUtil.getObject(map, "goodsDocDetailList");//物料明细信息
//
//            Map<String, Object> model = new LinkedHashMap<>();//金蝶其它出库model
//            model.put("FID", 0);//实体主键
//            model.put("FBillTypeID", new Document("FNUMBER", "QTCKD01_SYS"));//单据类型标准其它出出库单
//            model.put("FStockOrgId", new Document("FNumber", "100"));//库存组织，开发销售测试
//            model.put("FPickOrgId", new Document("FNumber", "100"));//领用组织
//            model.put("FStockDirect", "GENERAL");//库存方向（普通）
//            model.put("FDate", gmtCreate);//日期
//            model.put("FCustId", new Document("FNumber", "CUST0041"));//客户野象
//            model.put("FOwnerTypeIdHead", "BD_OwnerOrg");//货主类型
//            model.put("FOwnerIdHead", new Document("FNumber", "100"));//货主
//            model.put("FNote", goodsdocNo);//备注，先存放极客云出库单号
//            model.put("FBaseCurrId", new Document("FNumber", "PRE001"));//本位币
//
//            List<Map<String, Object>> FEntity = new ArrayList<>();//其它出库体数据
//            //循环添加物料信息
//            for (Map<String, Object> good : goodsDocDetailList) {
//                String goodsNo = VtuzxUtil.getString(good, "goodsNo");//货品编号
//                String unitName = VtuzxUtil.getString(good, "unitName");//单位名称
//                int quantity = VtuzxUtil.getInt(good, "quantity");//数量
//                //查询单位编码，直接传文字无效
//                String cond = String.format("Fname = '%s'", unitName);
//                List<VtuzxMap> bd_customer = kingdeeService.query(client, "BD_UNIT", new VtuzxArrayList<>(
//                        "FNumber",//单位编码
//                        "FNAME"//单位名称
//                ), cond);
//                String unit = "";
//                if (bd_customer != null && bd_customer.size() > 0) {
//                    unit = bd_customer.get(0).getString("FNumber");
//                }
//                Map<String, Object> entry = new LinkedHashMap<>();
//                entry.put("FMaterialId", new Document("FNumber", goodsNo));//物料编号
//                entry.put("FUnitID", new Document("FNumber", unit));//单位
//                entry.put("FQty", quantity);//实发数量
//                entry.put("FBaseUnitId", new Document("FNumber", unit));//基本单位
//                entry.put("FStockId", new Document("FNumber", "yx001"));//发货仓库先固定野象001
//                entry.put("FLot", new Document("FNumber", "88888"));//批号先默认
//                entry.put("FOwnerTypeId", "BD_OwnerOrg");//货主类型
//                entry.put("FOwnerId", new Document("FNumber", "100"));//货主
//                entry.put("FStockStatusId", new Document("FNumber", "KCZT01_SYS"));//库存状态
//                entry.put("FKeeperTypeId", "BD_KeeperOrg");//保管者类型
//                entry.put("FDistribution", false);//参加费用分配
//                entry.put("FKeeperId", new Document("FNumber", "100"));//保管者
//                FEntity.add(entry);
//            }
//            model.put("FEntity", FEntity);
//            Map<String, Object> kneeParam = new LinkedHashMap<>();
//            kneeParam.put("NeedUpDateFields", new ArrayList<>());
//            kneeParam.put("NeedReturnFields", new ArrayList<>());
//            kneeParam.put("IsDeleteEntry", true);
//            kneeParam.put("SubSystemId", "");
//            kneeParam.put("IsVerifyBaseDataField", true);
//            kneeParam.put("IsEntryBatchFill", false);
//            kneeParam.put("ValidateFlag", true);
//            kneeParam.put("NumberSearch", true);
//            kneeParam.put("InterationFlags", "");
//            kneeParam.put("Model", model);
//            //传金蝶其它出
//            try {
//                List<VtuzxMap> customerList = kingdeeService.save(client, "STK_MisDelivery", kneeParam);
//                VtuzxMap kingdeeCustomerMap = customerList.get(0);
//                String number = VtuzxUtil.getString(kingdeeCustomerMap, "Number");
//                kingdeeService.submit(client, "STK_MisDelivery", "0", number);
//                kingdeeService.audit(client, "STK_MisDelivery", "0", number, "STK_InvCheckResult");
//            } catch (Exception e) {
//                _logger.info(e.getMessage());
//            }
        }

        getStorageOut(from, to, pageIndex + 1);
    }

    @Override
    public void syncSerial() throws Exception {
        serialJky(0,50);
//        serialOne();
//        createInStock(0,50);
    }

    @Override
    public void syncSaleFinish(Date from, Date to, int pageIndex) throws Exception {
        _logger.info(String.format("导入%s - %s的销售数据(已完成)", VtuzxUtil.formatYmdHmsF(from), VtuzxUtil.formatYmdHmsF(to)));
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap saleMap = jiKeYunApiService.getSaleBill(storeDoc,
                new VtuzxMap("startModified", from)//最后修改时间
                        .append("endModified", to)//最后修改时间
                        .append("pageSize", 50)
                        .append("tradeStatus",9090)//单据状态已完成
                        .append("pageIndex", pageIndex)
                        .append("fields", "completeTime,couponFee,companyName,consignTime,isFit,tradeFrom,goodsSerial.subTradeId," +
                                "goodsSerial.skuId,goodsSerial.serialNo,warehouseName,warehouseCode,customerCode," +
                                "goodsDetail.goodsNo,goodsDetail.shareFavourableAfterFee,goodsDelivery.productionDate,goodsDelivery.expirationDate," +
                                "goodsDelivery.batchNo,tradeNo,tradeStatus,shopName,flagIds,sysFlagIds," +
                                "flagNames,tradeCount,shareFavourableFee,goodsDetail.unit," +
                                "goodsDetail.goodsName,goodsDetail.specName,goodsDetail.sellCount,departName," +
                                "goodsDetail.sellPrice,goodsDetail.taxRate,sellerMemo,gmtCreate,tradeTime,invoiceStatus,seller," +
                                "onlineTradeNo,appendMemo,buyerMemo,otherFee,discountFee,isGift,goodsMemo"));

//                new VtuzxMap()
//                        .append("tradeNo","")
//                        .append("pageSize", 50)
//                        .append("pageIndex", pageIndex)
//                        .append("fields", "couponFee,companyName,consignTime,isFit,tradeFrom,goodsSerial.subTradeId," +
//                                "goodsSerial.skuId,goodsSerial.serialNo,warehouseName,warehouseCode,customerCode," +
//                                "goodsDetail.goodsNo,goodsDetail.shareFavourableAfterFee,goodsDelivery.productionDate,goodsDelivery.expirationDate," +
//                                "goodsDelivery.batchNo,tradeNo,tradeStatus,shopName,flagIds,sysFlagIds,departName," +
//                                "flagNames,tradeCount,shareFavourableFee,goodsDetail.unit,goodsDetail.goodsName," +
//                                "goodsDetail.specName,goodsDetail.sellCount,goodsDetail.sellPrice,tradeTime,goodsDetail.taxRate," +
//                                "sellerMemo,gmtCreate,seller,onlineTradeNo,appendMemo,buyerMemo,otherFee,discountFee,isGift,goodsMemo"));
        System.out.println(pageIndex);
        Map<String, Object> result = VtuzxUtil.getObject(saleMap, "result");
        String tradeString = VtuzxUtil.getString(result,"data");
        if (VtuzxUtil.isEmpty(tradeString)){
            return;
        }
        Map<String,Object> tradeData = JSON.parseObject(tradeString,new TypeReference<HashMap<String,Object>>(){});
        JSONArray jsonArray = VtuzxUtil.getObject(tradeData,"Trades");
        List<String> tradeNoList = new ArrayList<>();//销售单号集合单集合
        List<Document> tradeList = new ArrayList<>();//需要添加到数据库的销售
        for (int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonTrades = (JSONObject) jsonArray.get(i);
            //吉客云的json首字母变成了大写,转成小写
            Map<String,Object> tradeMap = new HashMap<>();
            for (String key : jsonTrades.keySet()){
                String modifyKey = key.substring(0,1).toLowerCase() + key.substring(1);
                tradeMap.put(modifyKey,jsonTrades.get(key));
            }
            String tradeNo = VtuzxUtil.getString(tradeMap,"tradeNo");
            if(!tradeNoList.contains(tradeNo)){
                tradeNoList.add(tradeNo);
            }
//            Document oldSaleDoc = jikeyunSaleDao.findOne(Criteria.where("tradeNo").is(tradeNo));
            Document tradeDoc = new Document(tradeMap);
            //查询仓库金蝶仓库id
            String warehouseName = VtuzxUtil.getString(tradeDoc,"warehouseName");
            String stockId = getStockId(warehouseName, storeDoc);
            tradeDoc.append("stockId",stockId);
            String consignTime = VtuzxUtil.getString(tradeDoc,"consignTime");//发货日期
            Date consignDate = VtuzxUtil.parseDate(consignTime);
            tradeDoc.remove("consignTime");
            tradeDoc.append("consignTime",consignDate);

            //通过销售单号查询销售结算单获取客户名称，客户账号，结算时间，原订单金额，结算订单金额等数据
            //吉客云查询结算单无法查询多个
            String colsList = "[\"tradeSettleOrder.settleTime\",\"tradeSettleOrderDetailArr.sellTotal\",\"tradeSettleOrderDetailArr.shareFavourableAfterFee\",\"tradeSettleOrder.payment\",\"tradeSettleOrder.settleFee\",\"settleNo\",\"tradeSettleOrderCustomer.endCustomerAccount\",\"tradeSettleOrderCustomer.customerName\",\"tradeSettleOrderCustomer.customerAccount\"]";

            VtuzxMap settleMap = jiKeYunApiService.getTradeSettleAllInfo(storeDoc,
                    new VtuzxMap()
                            .append("tradeNo",tradeNo)
                            .append("cols",colsList));

            Map<String, Object> settleResult = VtuzxUtil.getObject(settleMap, "result");
            List<Map<String, Object>> settleData = VtuzxUtil.getObject(settleResult, "data");
            String customerName = "";
            if (!VtuzxUtil.isEmpty(settleData)){
                Map<String, Object> settle = settleData.get(0);
                Map<String,Object> tradeSettleOrder = VtuzxUtil.getObject(settle,"tradeSettleOrder");
                double payment = VtuzxUtil.getDouble(tradeSettleOrder,"payment");//原订单金额
                double settleFee = VtuzxUtil.getDouble(tradeSettleOrder,"settleFee");//原订单金额
                String settleTime = VtuzxUtil.getString(tradeSettleOrder,"settleTime");//结算时间
                Map<String,Object> tradeSettleOrderCustomer = VtuzxUtil.getObject(settle,"tradeSettleOrderCustomer");
                customerName = VtuzxUtil.getString(tradeSettleOrderCustomer,"customerName");//客户名称
                String customerAccount = VtuzxUtil.getString(tradeSettleOrderCustomer,"customerAccount");//客户账号
                tradeDoc.append("payment",payment)
                        .append("settleFee",settleFee)
                        .append("settleTime",VtuzxUtil.parseDate(settleTime));

                Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
                Matcher m = p.matcher(customerName);
                if(!m.find() && customerName.length() > 8){//说明是加密的
                    tradeDoc.append("customerName","加密客户")
                            .append("customerAccount","加密账号");
                } else {
                    tradeDoc.append("customerName",customerName)
                            .append("customerAccount",customerAccount);
                }
            }
            tradeList.add(tradeDoc);
        }

        //删除已有的数据然后添加新的数据
        jikeyunSaleDao.deleteMany(Criteria.where("tradeNo").in(tradeNoList));
        jikeyunSaleDao.insertMany(tradeList);
        //修改追溯链信息
        for (Document tradeDoc : tradeList){
            int tradeStatus = VtuzxUtil.getInt(tradeDoc, "tradeStatus");//订单状态
            String flagName = VtuzxUtil.getString(tradeDoc, "flagNames"); //标记
            String tradeNo = VtuzxUtil.getString(tradeDoc, "tradeNo"); //销售单号
            String shopName = VtuzxUtil.getString(tradeDoc, "shopName");//店铺名称(销售渠道)
            String warehouseName = VtuzxUtil.getString(tradeDoc,"warehouseName");
            String consignTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(tradeDoc,"consignTime"));
            int tradeFrom = VtuzxUtil.getInt(tradeDoc,"tradeFrom");//订单来源，1网店
            if (!flagName.contains("售后")) {
                if (!flagName.contains("寄存")) {
                    if ((tradeStatus == 9090 || tradeStatus == 6000) && !flagName.contains("补称")) { //订单状态是发货在途、已完成
                        List<Map<String, Object>> goodsSerials = VtuzxUtil.getObject(tradeDoc, "goodsSerials");
                        if (!VtuzxUtil.isEmpty(goodsSerials)) {
                            for (Map<String, Object> serialData : goodsSerials) {
                                String serialNo = VtuzxUtil.getString(serialData, "SerialNo");
                                if (!VtuzxUtil.isEmpty(serialNo)) {
                                    if (serialNo.startsWith("HTTP://ZS")) {
                                        if (!warehouseName.equals("电商——物流出库仓库") && !"外埠物流仓库".equals(warehouseName)) {//发货仓库非网购仓库填写追溯链信息
                                            StringBuilder sb = new StringBuilder(serialNo.toLowerCase());
                                            sb.setCharAt(49, 'Z');
                                            sb.setCharAt(44, 'C');
                                            String newSerialNo = sb.toString();
                                            Document updateDoc = new Document();
                                            updateDoc.append("saleChnnel", shopName)//销售渠道
                                                    .append("saleTime", consignTime)//发货时间
                                                    .append("lastTime", consignTime)//最后操作时间
                                                    .append("tradeNo", tradeNo);
                                            serialData.replace("serialNo", newSerialNo);
                                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo), updateDoc);
                                            _logger.info(String.format("添加追溯链信息[%s]", serialNo));
//                                            System.out.println("追溯链" + newSerialNo);
                                        }
                                        if ("外埠物流仓库".equals(warehouseName)) {//如果发货仓库是外部物流仓库
                                            String customerCode = VtuzxUtil.getString(tradeDoc, "customerCode");
                                            //从客户列表查询客户名称
                                            VtuzxMap customerMap = jiKeYunApiService.customerList(storeDoc, new VtuzxMap("customerCode", customerCode));
                                            Map<String, Object> customerResult = VtuzxUtil.getObject(customerMap, "result");
                                            List<Map<String, Object>> customerData = VtuzxUtil.getObject(customerResult, "data");
//                                            List<Map<String, Object>> customers = VtuzxUtil.getObject(customerData, "trades");
                                            String customerName = VtuzxUtil.getString(customerData.get(0), "nickname");
                                            StringBuilder sb = new StringBuilder(serialNo.toLowerCase());
                                            sb.setCharAt(49, 'Z');
                                            sb.setCharAt(44, 'C');
                                            String newSerialNo = sb.toString();
                                            Document updateDoc = new Document();
                                            updateDoc.append("saleChnnel", customerName)//销售渠道
                                                    .append("saleTime", consignTime)//发货时间
                                                    .append("lastTime", consignTime)//最后操作时间
                                                    .append("tradeNo", tradeNo);
                                            serialData.replace("serialNo", newSerialNo);
                                            traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo), updateDoc);
                                            _logger.info(String.format("添加追溯链信息[%s]", serialNo));
//                                            System.out.println("追溯链" + newSerialNo);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }


        syncSaleFinish(from,to,pageIndex + 1);
    }

    @Override
    public void syncChannel(Date from, Date to, int pageIndex) throws Exception{
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap channelMap = jiKeYunApiService.getChannel(storeDoc,
                new VtuzxMap()
                        .append("pageSize",50)
                        .append("pageIndex",pageIndex));
        Map<String, Object> result = VtuzxUtil.getObject(channelMap, "result");
        Map<String,Object> data = VtuzxUtil.getObject(result,"data");
        List<Map<String,Object>> channelInfoList = VtuzxUtil.getObject(data,"salesChannelInfo");
        if (VtuzxUtil.isEmpty(channelInfoList)){
            return;
        }
        List<Document> channelList = new ArrayList<>();
        List<String> channelIdList = new ArrayList<>();//渠道id集合
        for (Map<String,Object> channel : channelInfoList){
            String channelName = VtuzxUtil.getString(channel,"channelName");//销售渠道
            String companyName = VtuzxUtil.getString(channel,"companyName");//公司
            String channelId = VtuzxUtil.getString(channel,"channelId");//渠道id
            String channelDepartName = VtuzxUtil.getString(channel,"channelDepartName");//负责部门名称
            String warehouseName = VtuzxUtil.getString(channel,"warehouseName");//默认仓库名称
            String warehouseCode = VtuzxUtil.getString(channel,"warehouseCode");//默认仓库名称
            String channelDepartId = VtuzxUtil.getString(channel,"channelDepartId");//部门id
            String memo = VtuzxUtil.getString(channel,"memo");//备注
            String channelGroup = "";//渠道分组
            Document document = new Document();
            document.append("channelName",channelName)
                    .append("channelId",channelId)
                    .append("warehouseCode",warehouseCode)
                    .append("warehouseName",warehouseName)
                    .append("channelDepartId",channelDepartId)
                    .append("memo",memo)
                    .append("companyName",companyName);
            if (channelDepartName.startsWith("bb")){
                channelGroup = "本埠";
            } else if (channelDepartName.contains("外埠")){
                channelGroup = "外埠";
            } else {
                channelGroup = channelDepartName;
            }
            document.append("channelGroup",channelGroup);//渠道分组
            if(!channelIdList.contains(channelId)){
                channelIdList.add(channelId);
            }
            channelList.add(document);
        }
        //先删除已存在的数据然后添加
        channelDao.deleteMany(Criteria.where("channelId").in(channelIdList));
        channelDao.insertMany(channelList);
        syncChannel(from,to,pageIndex + 1);
    }

    @Override
    public void syncPriceList(int pageIndex,ObjectId userId,String name) throws Exception {
        VtuzxMap param = new VtuzxMap();
        param.append("pageSize", 50)
                .append("pageIndex", pageIndex);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap payAndCol = jiKeYunApiService.getPriceList(storeDoc, param);
        Map<String, Object> result = (LinkedHashMap) payAndCol.get("result");
        Map<String, Object> data = (LinkedHashMap) result.get("data");
        List<Map<String,Object>> skuprice = VtuzxUtil.getObject(data, "skuprice");
        if (skuprice.size() <= 0) {
            return;
        }
        //向数据库添加新的数据,并且把原本的数据删除添加到价目表日志集合中
        List<Document> priceList = new ArrayList<>();
        for (Map<String,Object> map : skuprice){
            String goodsNo = (String) map.get("goodsNo");
            String skuName = (String) map.get("skuName");//规格
            String goodsName = (String) map.get("goodsName");//货品名称
            String unitName = (String) map.get("unitName");//单位名称
            Double price5 = 0.0;
            if (!VtuzxUtil.isEmpty(map.get("price5"))){
                price5 = Double.parseDouble(map.get("price5").toString());//当前成本价
                DecimalFormat df = new DecimalFormat("#.00");
                price5 = Double.parseDouble(df.format(price5));
            }
            Double price16 = 0.0;
            if (!VtuzxUtil.isEmpty(map.get("price16"))){
                price16 = Double.parseDouble(map.get("price16").toString());//标准成本价
                DecimalFormat df = new DecimalFormat("#.00");
                price16 = Double.parseDouble(df.format(price16));
            }


            Document material = new Document();
            material.append("materialNo",goodsNo)
                    .append("materialName",goodsName)
                    .append("unit",unitName)
                    .append("userName",name)
                    .append("userId",userId)
                    .append("specification",skuName)
                    .append("standardPrice",price16)//标准成本价
                    .append("currentPrice",price5);//当前成本价
            priceList.add(material);
        }
        priceListDao.insertMany(priceList);


        syncPriceList(pageIndex + 1,userId,name);
    }

    @Override
    public void syncSaleBillDeposit(Date from, Date to, int pageIndex) throws  Exception {
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));

        VtuzxMap saleMap = jiKeYunApiService.getSaleBill(storeDoc,
                new VtuzxMap("startCreated", from)//创建时间开始
                        .append("endCreated", to)//创建时间
                        .append("pageSize", 50)
                        .append("tradeStatus",5030)//单据状态已取消被拆分
                        .append("pageIndex", pageIndex)
                        .append("fields", "completeTime,couponFee,companyName,consignTime,isFit,tradeFrom,goodsSerial.subTradeId," +
                                "goodsSerial.skuId,goodsSerial.serialNo,warehouseName,warehouseCode,customerCode," +
                                "goodsDetail.goodsNo,goodsDetail.shareFavourableAfterFee,goodsDelivery.productionDate,goodsDelivery.expirationDate," +
                                "goodsDelivery.batchNo,tradeNo,tradeStatus,shopName,flagIds,sysFlagIds," +
                                "flagNames,tradeCount,shareFavourableFee,goodsDetail.unit,departName," +
                                "goodsDetail.goodsName,goodsDetail.specName,goodsDetail.sellCount," +
                                "goodsDetail.sellPrice,goodsDetail.taxRate,sellerMemo,gmtCreate,tradeTime,invoiceStatus,seller," +
                                "onlineTradeNo,appendMemo,buyerMemo,otherFee,discountFee,isGift,goodsMemo"));


        Map<String, Object> result = VtuzxUtil.getObject(saleMap, "result");
        String tradeString = VtuzxUtil.getString(result,"data");
        if (VtuzxUtil.isEmpty(tradeString)){
            return;
        }
        Map<String,Object> tradeData = JSON.parseObject(tradeString,new TypeReference<HashMap<String,Object>>(){});
        JSONArray jsonArray = VtuzxUtil.getObject(tradeData,"Trades");
        List<String> tradeNoList = new ArrayList<>();//销售单号集合单集合
        List<Document> tradeList = new ArrayList<>();//需要添加到数据库的销售
        for (int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonTrades = (JSONObject) jsonArray.get(i);
            //吉客云的json首字母变成了大写,转成小写
            Map<String,Object> tradeMap = new HashMap<>();
            for (String key : jsonTrades.keySet()){
                String modifyKey = key.substring(0,1).toLowerCase() + key.substring(1);
                tradeMap.put(modifyKey,jsonTrades.get(key));
            }
            String tradeNo = VtuzxUtil.getString(tradeMap,"tradeNo");
            if(!tradeNoList.contains(tradeNo)){
                tradeNoList.add(tradeNo);
            }
//            Document oldSaleDoc = jikeyunSaleDao.findOne(Criteria.where("tradeNo").is(tradeNo));
            Document tradeDoc = new Document(tradeMap);
            //查询仓库金蝶仓库id
            String warehouseName = VtuzxUtil.getString(tradeDoc,"warehouseName");
            String stockId = getStockId(warehouseName, storeDoc);
            tradeDoc.append("stockId",stockId);
            String consignTime = VtuzxUtil.getString(tradeDoc,"consignTime");//发货日期
            Date consignDate = VtuzxUtil.parseDate(consignTime);
            tradeDoc.remove("consignTime");
            tradeDoc.append("consignTime",consignDate);

            //通过销售单号查询销售结算单获取客户名称，客户账号，结算时间，原订单金额，结算订单金额等数据
            //吉客云查询结算单无法查询多个
            String colsList = "[\"tradeSettleOrder.settleTime\",\"tradeSettleOrderDetailArr.sellTotal\",\"tradeSettleOrderDetailArr.shareFavourableAfterFee\",\"tradeSettleOrder.payment\",\"tradeSettleOrder.settleFee\",\"settleNo\",\"tradeSettleOrderCustomer.endCustomerAccount\",\"tradeSettleOrderCustomer.customerName\",\"tradeSettleOrderCustomer.customerAccount\"]";

            VtuzxMap settleMap = jiKeYunApiService.getTradeSettleAllInfo(storeDoc,
                    new VtuzxMap()
                            .append("tradeNo",tradeNo)
                            .append("cols",colsList));

            Map<String, Object> settleResult = VtuzxUtil.getObject(settleMap, "result");
            List<Map<String, Object>> settleData = VtuzxUtil.getObject(settleResult, "data");
            String customerName = "";
            if (!VtuzxUtil.isEmpty(settleData)){
                Map<String, Object> settle = settleData.get(0);
                Map<String,Object> tradeSettleOrder = VtuzxUtil.getObject(settle,"tradeSettleOrder");
                double payment = VtuzxUtil.getDouble(tradeSettleOrder,"payment");//原订单金额
                double settleFee = VtuzxUtil.getDouble(tradeSettleOrder,"settleFee");//原订单金额
                String settleTime = VtuzxUtil.getString(tradeSettleOrder,"settleTime");//结算时间
                Map<String,Object> tradeSettleOrderCustomer = VtuzxUtil.getObject(settle,"tradeSettleOrderCustomer");
                customerName = VtuzxUtil.getString(tradeSettleOrderCustomer,"customerName");//客户名称
                String customerAccount = VtuzxUtil.getString(tradeSettleOrderCustomer,"customerAccount");//客户账号
                tradeDoc.append("payment",payment)
                        .append("settleFee",settleFee)
                        .append("settleTime",VtuzxUtil.parseDate(settleTime));

                Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
                Matcher m = p.matcher(customerName);
                if(!m.find() && customerName.length() > 8){//说明是加密的
                    tradeDoc.append("customerName","加密客户")
                            .append("customerAccount","加密账号");
                } else {
                    tradeDoc.append("customerName",customerName)
                            .append("customerAccount",customerAccount);
                }
            }
            tradeList.add(tradeDoc);
        }

        //删除已有的数据然后添加新的数据
        jikeyunSaleDao.deleteMany(Criteria.where("tradeNo").in(tradeNoList));
        jikeyunSaleDao.insertMany(tradeList);



        syncSaleBillDeposit(from,to,pageIndex + 1);

    }

    @Override
    public void syncInventory(Date from, Date to, int i) throws Exception {
        List<String> stockNoList = new ArrayList<>();
        stockNoList.add("001");//原料二号库
        stockNoList.add("010");//原料三号库
        stockNoList.add("014");//原料四号库
        stockNoList.add("012");//原料五号库
        stockNoList.add("023");//原料七号库
        stockNoList.add("006");//干参半成品一号库
        stockNoList.add("002");//干参半成品二号库
        stockNoList.add("019");//干参半成品三号库
        stockNoList.add("017");//干参半成品四号库
        stockNoList.add("011");//包材辅料内包四楼
        stockNoList.add("003");//即食海参半成品12号库
        stockNoList.add("004");//即食海参半成品8号库
        stockNoList.add("005");//即食海参半成品6号库
        stockNoList.add("016");//即食海参成品11号库

        //根据仓库添加数据
        for (String stockNo : stockNoList){
            String billNo = IXqcConst.createBillNo(BillType.TBKC);
            Criteria cond = new Criteria();
            cond.and("stockNo").is(stockNo);
            Iterator<Document>  inventoryItr = inventoryDao.findList(cond, new Document("createTime", 1), 0, 0);
            List<ObjectId> ids = new ArrayList<>();
            List<String> materialList = new ArrayList<>();
            VtuzxMap data = new VtuzxMap();
            while (inventoryItr.hasNext()) {
                Document statDoc = inventoryItr.next();
                ObjectId id = VtuzxUtil.getObject(statDoc, "_id");
                String materialNumber = VtuzxUtil.getString(statDoc, "materialNo");
                String stockNum = VtuzxUtil.getString(statDoc, "stockNo");
                String batchNum = VtuzxUtil.getString(statDoc, "batchNo");
                int boxCount = VtuzxUtil.getInt(statDoc, "boxCount");
                Double count = VtuzxUtil.getDouble(statDoc, "count");
                data.append(id.toString(), new VtuzxMap("materialNo", materialNumber).append("stockNo", stockNum).append("batchNo", batchNum).append("boxCount", boxCount).append("count", count));

                materialList.add(materialNumber);
                //ids.add(FastUtil.convertId(id));
                ids.add(id);
            }

            List<VtuzxMap> detailList = new ArrayList<>();
            Iterator<Document> inventoryDetailItr = inventoryDetailDao.findList(Criteria.where("_inventoryId").in(ids).and("status").is("in"), new Document("createTime", -1), 0, 0);

            while (inventoryDetailItr.hasNext()) {
                Document detailDoc = inventoryDetailItr.next();
                VtuzxMap detailMap = new VtuzxMap(detailDoc);
                detailMap.append("inventoryId", VtuzxUtil.removeString(detailMap, "_inventoryId"));
                detailList.add(detailMap);
            }

            VtuzxMap materialMap = new VtuzxMap();
            Iterator<Document> materialItr = materialDao.findList(Criteria.where("fNumber").in(materialList), null, 0, 0);
            while (materialItr.hasNext()) {
                Document mtr = materialItr.next();
                VtuzxMap mtrMap = new VtuzxMap();
                String materialNumber = VtuzxUtil.getString(mtr, "fNumber");
                String materialName = VtuzxUtil.getString(mtr, "fName");
                String fSpecification = VtuzxUtil.getString(mtr, "fSpecification");
                String fBaseUnitIdFName = VtuzxUtil.getString(mtr, "fBaseUnitIdFName");
                mtrMap.append("materialName", materialName);
                mtrMap.append("materialSpec", fSpecification);
                mtrMap.append("unit", fBaseUnitIdFName);
                mtrMap.append("materialNo", materialNumber);
                materialMap.append(materialNumber, mtrMap);
            }
            Document stock = stockDao.findOne(Criteria.where("fNumber").is(stockNo));
            String stockName = VtuzxUtil.getString(stock, "fName");
            VtuzxMap res = new VtuzxMap();
            List<Document> resList = new ArrayList<>();
            for (VtuzxMap detail: detailList) {
                String inventoryId = VtuzxUtil.getString(detail, "inventoryId");
                VtuzxMap inventoryMap = VtuzxUtil.getObject(data, inventoryId);

                String dMaterialNo = VtuzxUtil.getString(inventoryMap, "materialNo");
                VtuzxMap materials = VtuzxUtil.getObject(materialMap, dMaterialNo);
                String materialName = "";
                String materialSpec = "";
                String unit = "";
                if (!VtuzxUtil.isEmpty(materials)) {
                    materialName = VtuzxUtil.getString(materials, "materialName");
                    materialSpec = VtuzxUtil.getString(materials, "materialSpec");
                    unit = VtuzxUtil.getString(materials, "unit");
                }

                String dLocationNo = VtuzxUtil.getString(detail, "locationNo");
                String dStockNo = VtuzxUtil.getString(detail, "stockNo");
                String dBatchNo = VtuzxUtil.getString(inventoryMap, "batchNo");
                double count = VtuzxUtil.getDouble(detail, "count");
                String key = dMaterialNo + '_' + dLocationNo + '_' + dStockNo + '_' + dBatchNo;
                Document resMap = VtuzxUtil.getObject(res, key);
                if (resMap == null) {
                    Document newDetail = new Document("materialNo", dMaterialNo)
                            .append("materialName", materialName)
                            .append("materialSpec", materialSpec)
                            .append("unit", unit)
                            .append("locationNo", dLocationNo)
                            .append("stockNo", dStockNo)
                            .append("stockName", stockName)
                            .append("batchNo", dBatchNo)
                            .append("boxCount", 1)
                            .append("billNo",billNo)//单据编号和外层表关联
                            .append("count", count);
                    res.append(key, newDetail);
                    resList.add(newDetail);
                } else {
                    int resBoxCount = VtuzxUtil.getInt(resMap, "boxCount");
                    double resCount = VtuzxUtil.getDouble(resMap, "count");
                    resMap.append("boxCount", ++resBoxCount);
                    resMap.append("count", resCount + count);
                }
            }
            //添加外层数据和内层数据

            Document regularDoc = new Document();
            regularDoc.append("billNo",billNo)
                    .append("stockNo",stockNo)
                    .append("stockName",stockName)
                    .append("syncTime",from);
            inventoryRegularDao.insertOne(regularDoc);
            inventoryRegularDetailDao.insertMany(resList);
        }

    }

    /**
     * 查询吉客云出库单并创建入库申请单
     * @param from
     * @param to
     * @param pageIndex
     * @throws Exception
     */
    @Override
    public void getStorageOutAndStockIn(Date from, Date to, int pageIndex) throws Exception {
        _logger.info("查询吉客云出库单");
        //查询极客云公出库单
        VtuzxMap param = new VtuzxMap();
        //需要返回的字段
        String selelctFields = "goodsdocNo,inOutDate,userName,channelName,channelId,channelCode," +
                "gmtCreate,inouttypeName,vendCustomerName," +
                "warehouseCode,warehouseName,comment," +
                "companyName,inOutReason,goodsDocDetailList.recId," +
                "goodsDocDetailList.goodsNo," +
                "goodsDocDetailList.goodsName,goodsDocDetailList.skuId," +
                "goodsDocDetailList.skuName,goodsDocDetailList.skuBarcode," +
                "goodsDocDetailList.unitName,goodsDocDetailList.quantity," +
                "goodsDocDetailList.serialNo";
        param.append("startDate", VtuzxUtil.formatYmdHmsF(from))
                .append("endDate", VtuzxUtil.formatYmdHmsF(to))
                .append("pageSize", 50)
//                .append("goodsDocNo", "CRK202503190033")//出库单号
                .append("warehouseCode","YXWB01")//出库仓库为外埠物流仓
                .append("selelctFields", selelctFields)
                .append("pageIndex", pageIndex);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap stotrageDoc = jiKeYunApiService.getStorageOut(storeDoc, param);
        Map<String, Object> result = VtuzxUtil.getObject(stotrageDoc, "result");
        List<Map<String, Object>> data = VtuzxUtil.getObject(result, "data");
        if (data.size() <= 0) {
            return;
        }
        List<String> channelIdList = new ArrayList<>();
        Iterator<Document> channelItr = channelDao.findList(Criteria.where("memo").regex("转入库单"), null, 0, 0);
        while (channelItr.hasNext()){
            Document channelDoc = channelItr.next();
            String channelId = VtuzxUtil.getString(channelDoc,"channelId");
            if (!channelIdList.contains(channelId)){
                channelIdList.add(channelId);
            }
        }

        List<Document> storageList = new ArrayList<>();
        List<String> goodsNoList = new ArrayList<>();//出库单号集合

//        channelIdList.add("2162466254387709184");
//        channelIdList.add("2170454728001028992");
//        channelIdList.add("2170484626425578880");
//        channelIdList.add("2187860620156896256");
//        channelIdList.add("2189310637665846528");//外埠-2205001 天津 天津 杨军
//        channelIdList.add("2213029758236526336");//外埠-4114001 河南 洛阳 张建成
//        channelIdList.add("2215458851072409856");//外埠-3505001 安徽 合肥 张东东
//        channelIdList.add("2238553553551853952");//外埠-3313001 江苏 淮安 侯少专
        for (Map<String, Object> map : data) {
            Document outDoc = new Document(map);
            String goodsdocNo = VtuzxUtil.getString(outDoc,"goodsdocNo");//出库单号
            String channelId = VtuzxUtil.getString(outDoc,"channelId");//渠道id
            //只要对应渠道的，
            if (channelIdList.contains(channelId)){
                if(!goodsNoList.contains(goodsdocNo)){
                    goodsNoList.add(goodsdocNo);
                }
                storageList.add(outDoc);
            }

        }
        //查询后先保存到中台数据库
        //先判断是否有重复数据
        long goodsDocCount = storageOutDao.count(new Criteria("goodsdocNo").in(goodsNoList));
        if (goodsDocCount > 0){
            storageOutDao.deleteMany(new Criteria("goodsdocNo").in(goodsNoList));
        }
        storageOutDao.insertMany(storageList);
        syncCreateStockIn(storageList,storeDoc);
        getStorageOutAndStockIn(from, to, pageIndex + 1);
    }

    /**
     * 创建吉客云入库申请单
     */
    public void syncCreateStockIn(List<Document> storageList,Document storeDoc) throws Exception{
        for (Document storageDoc : storageList){
            String userName = VtuzxUtil.getString(storageDoc,"userName");//出库单创建人名称
            String goodsdocNo = VtuzxUtil.getString(storageDoc,"goodsdocNo");//出库单号
            String channelCode = VtuzxUtil.getString(storageDoc,"channelCode");//渠道编码
            List<Map<String,Object>> goodsDocDetailList = VtuzxUtil.getObject(storageDoc,"goodsDocDetailList");//货品信息
//            Document channelDoc = channelDao.findOne(Criteria.where("channelName").is(channelName));
//            String warehouseCode = VtuzxUtil.getString(channelDoc,"warehouseCode");//渠道对应的默认仓库编码
            VtuzxMap channelMap = jiKeYunApiService.getChannel(storeDoc,
                    new VtuzxMap()
                            .append("pageSize",50)
                            .append("code",channelCode));
            Map<String, Object> channelResult = VtuzxUtil.getObject(channelMap, "result");
            Map<String,Object> channelData = VtuzxUtil.getObject(channelResult,"data");
            List<Map<String,Object>> channelInfoList = VtuzxUtil.getObject(channelData,"salesChannelInfo");
            String warehouseCode = VtuzxUtil.getString(channelInfoList.get(0),"warehouseCode");//渠道对应的默认仓库编码

            VtuzxMap param = new VtuzxMap();
            param.append("memo","采购入库")//备注
                    .append("source","OPEN")
                    .append("operator",userName)//制单人姓名(出库单创建人名称)
                    .append("inType",101)//入库类型采购入库
                    .append("inWarehouseCode",warehouseCode)//入库仓库编号
                    .append("applyUserName",userName)//申请人姓名
                    .append("inReason","外埠经销商订货入库")//入库原因
                    .append("vendCode","YX01")//供应商编号默认野象
                    .append("relDataId",goodsdocNo)//关联单据id，没有的话传0
                    .append("currencyRate",1)//汇率
                    .append("applyDate",new Date());//申请入库时间
            List<VtuzxMap> goodList = new ArrayList<>();//货品信息
            for (Map<String,Object> goodsMap : goodsDocDetailList){
                String serialNo = VtuzxUtil.getString(goodsMap,"serialNo");//唯一码
                String goodsNo = VtuzxUtil.getString(goodsMap,"goodsNo");//货品编码
                double quantity = VtuzxUtil.getDouble(goodsMap,"quantity");//货品数量
                double unitName = VtuzxUtil.getDouble(goodsMap,"unitName");//货品单位
                VtuzxMap stockInDetailViews = new VtuzxMap();
                List<VtuzxMap> serialList = new ArrayList<>();//唯一码集合
                //判断是否有唯一码
                if(!VtuzxUtil.isEmpty(serialNo)){
                    stockInDetailViews.append("isSerial",1);
                    VtuzxMap serialMap = new VtuzxMap();
                    serialMap.append("serialNo",serialNo)//唯一码
                            .append("quantity",1);//数量
                    serialList.add(serialMap);
                } else {
                    stockInDetailViews.append("isSerial",0);
                }
                //查询经销商供货价
                Double goodPrice = getGoodPrice(goodsNo);

                stockInDetailViews.append("skuCount",quantity);//入库申请数量
                stockInDetailViews.append("unitName",unitName);//入库申请数量
                stockInDetailViews.append("skuPrice",goodPrice);//货品入库价格
                stockInDetailViews.append("isCertified",1);//是否正品
                stockInDetailViews.append("relDetailId",0);//上游单据的明细id
                stockInDetailViews.append("isBatch",0);//是否启用批次
                stockInDetailViews.append("goodsNo",goodsNo);//货品编号
                stockInDetailViews.append("skuBarcode",goodsNo);//条码
                if (!VtuzxUtil.isEmpty(serialList)){
                    stockInDetailViews.append("serialList",serialList);
                }
                goodList.add(stockInDetailViews);
            }
            param.append("stockInDetailViews",goodList);


            try {
                VtuzxMap storageOut = jiKeYunApiService.createStockInApply(storeDoc, param);
                //获取入库申请单号
                Map<String,Object> result = VtuzxUtil.getObject(storageOut,"result");
                Map<String,Object> data = VtuzxUtil.getObject(result,"data");
                String inNo = VtuzxUtil.getString(data,"inNo");//入库申请单号
                storageDoc.append("syncInfo",true)//传单状态为成功
                        .append("inNo",inNo);//入库申请单号
                storageOutDao.updateOne(Criteria.where("goodsdocNo").is(goodsdocNo),storageDoc);
            } catch (Exception e){
                //失败的话反写失败原因
                storageDoc.append("message",e.getMessage())
                        .append("syncInfo",false);
                storageOutDao.updateOne(Criteria.where("goodsdocNo").is(goodsdocNo),storageDoc);
                _logger.info(e.getMessage());
            }
        }

    }

    /**
     * 查询货品
     * @param goodsNo
     * @return
     * @throws Exception
     */
    private Double getGoodPrice(String goodsNo) throws Exception{
        VtuzxMap param = new VtuzxMap();
        param.append("goodsNo", goodsNo);
        //获取token
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap payAndCol = jiKeYunApiService.getPriceList(storeDoc, param);
        Map<String, Object> result = (LinkedHashMap) payAndCol.get("result");
        Map<String, Object> data = (LinkedHashMap) result.get("data");
        List<Map<String,Object>> skupriceList = VtuzxUtil.getObject(data, "skuprice");
        double skuPrice = 0.0;
        if (!VtuzxUtil.isEmpty(skupriceList)){
            skuPrice = VtuzxUtil.getDouble(skupriceList.get(0),"price4");
        }

        return skuPrice;
    }

    private void serialJky(int start, int limit) throws Exception {
//        String startTime = "2023-05-25 13:30:00";
//        String endTime = "2023-05-25 13:50:59";
        Criteria cond = new Criteria();
//        cond.and("createTime").gte(VtuzxUtil.parseDate(startTime)).lte(VtuzxUtil.parseDate(endTime));
        String prdInBillNo = "CJRK230729085705159";
        Iterator<Document> prdInItr = prdInDetailBoxDao.findList(Criteria.where("billNo").is(prdInBillNo),null,0,0);
        List<String> boxList = new ArrayList<>();
        while (prdInItr.hasNext()){
            Document prdInDoc = prdInItr.next();
            String boxNo = VtuzxUtil.getString(prdInDoc,"boxNo");
            boxList.add(boxNo);
        }
        cond.and("boxNo").in(boxList);
        Iterator<Document> inventoryItr = inventoryDetailDao.findList(cond, new Document("createTime", -1), start, limit);
        List<VtuzxMap> inventoryList = new ArrayList<>();
        int size = 0;
        while (inventoryItr.hasNext()) {
            size++;
            Document inventoryDoc = inventoryItr.next();
            List<VtuzxMap> trac = null;
            try {
                trac = VtuzxUtil.getObject(inventoryDoc, "traceBack");
            } catch (ClassCastException e) {
                e.printStackTrace();
            }

            if (trac != null && trac.size() > 0) {
                VtuzxMap inventoryMap = new VtuzxMap(inventoryDoc);
                inventoryList.add(inventoryMap);
            }
        }
        BillType billType = BillType.SCRK;
        //获取令牌
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        for (VtuzxMap invMap : inventoryList) {
            String boxNo = VtuzxUtil.getString(invMap, "boxNo");

            List<Document> traceBack = VtuzxUtil.getObject(invMap, "traceBack");
            String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(invMap, "createTime"));

            String inventoryId = VtuzxUtil.getString(invMap, "_inventoryId");
            //从外层表中取出物料信息
            Document invenDoc = inventoryDao.findById(inventoryId);
            String materialNo = VtuzxUtil.getString(invenDoc, "materialNo");
            if ("04030307010".equals(materialNo)){
                materialNo = "04030307009";
            }
            List<VtuzxMap> boxSerialList = new ArrayList<>();//箱子接口唯一码参数
            List<String> traceBackList = new ArrayList<>();//存储整理后的追溯码
            for (Document trace : traceBack) {

                String traceNo = VtuzxUtil.getString(trace, "traceBackNo");
                traceBackList.add(traceNo);
                VtuzxMap traceMap = new VtuzxMap("sn", traceNo);
                boxSerialList.add(traceMap);

            }
            //把唯一码整理成string类型的
            String stringFromList = String.join(",", traceBackList);
            VtuzxMap goodsMap = new VtuzxMap();//getGoodsList方法返回值
            //需要先获取条码(skubarcode)
            VtuzxMap goodsParam = new VtuzxMap();
            goodsParam.append("pageIndex", 0)
                    .append("pageSize", 1)
                    .append("goodsNo", materialNo);
            try {
                goodsMap = iJiKeYunApiService.getGoodsList(storeDoc, goodsParam);
            } catch (Exception e) {
                throw new VtuzxException(e.getMessage());
            }

            LinkedHashMap result = VtuzxUtil.getObject(goodsMap, "result");
            LinkedHashMap data = VtuzxUtil.getObject((Map<String, Object>) result, "data");
            List<LinkedHashMap> goods = VtuzxUtil.getObject((Map<String, Object>) data, "goods");
            if (goods != null && goods.size() > 0) {
                LinkedHashMap goodsResult = goods.get(0);
                String materialModel = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuName");
                String skuId = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuId");
                //传入唯一码
                //查询规格
                Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
                String materialName = VtuzxUtil.getString(materialDoc, "fName");
                VtuzxMap bizcontent = new VtuzxMap();//业务请求参数
                bizcontent.append("goodsNo", materialNo)
                        .append("skuName", materialModel)
                        .append("serialNoList", stringFromList)
                        .append("snDefine1", VtuzxUtil.formatYmdHmsF(new Date()))
                        .append("snDefine2", createTime);//生产日期
                if (!VtuzxUtil.isEmpty(stringFromList)) {
                    try {
                        iJiKeYunApiService.serialNoAdd(storeDoc, bizcontent);
                    } catch (Exception e) {
                        _logger.info(e.getMessage());
                    }
                }
                //创建箱子
                VtuzxMap boxParam = new VtuzxMap();//箱码总参数
                List<VtuzxMap> boxDetailList = new ArrayList<>();//入库申请单明细
                Document prdColDetail = prdColDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
                if (!VtuzxUtil.isEmpty(prdColDetail)){
                    String id = VtuzxUtil.getString(prdColDetail,"_id");
                    String batchNo = VtuzxUtil.getString(prdColDetail,"batchNo");
                    double count = VtuzxUtil.getDouble(prdColDetail,"count");


                    int serialCount = boxSerialList.size();//每个箱子的唯一码数量
                    boxDetailList.add(new VtuzxMap("goodsNo", materialNo)
                            .append("goodsName", materialName)
                            .append("skuId", skuId)
                            .append("boxCount", serialCount)
                            .append("snList", boxSerialList));
                    boxParam.append("boxCount", 1)
                            .append("boxDetailList", boxDetailList)
                            .append("isAuto", 3)
                            .append("boxNo", billType.barcodeKey() + "|;" + id + "|;" + materialNo + "|;" + batchNo + "|;" + count +"|;" +boxNo);

                    if (boxSerialList.size() > 0 && boxSerialList != null) {
                        try {
                            iJiKeYunApiService.createBoxBatch(storeDoc, boxParam);
                        } catch (Exception e) {
                            _logger.info(e.getMessage());
                        }
                    }
                }

            }

        }

        System.out.println(start + "-------------" + size);
        if (size >= limit) {
            serialJky(start + 1, limit);

        } else {
            String ss = "没有数据了";
        }
    }

    private void serialOne() throws Exception {
        BillType billType = BillType.SCRK;
        Criteria cond = new Criteria();
        cond.and("boxNo").is("A021690427230506");
        Document inventoryDoc = inventoryDetailDao.findOne(cond);

        //获取令牌
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));

        String boxNo = VtuzxUtil.getString(inventoryDoc, "boxNo");
        List<Document> traceBack = VtuzxUtil.getObject(inventoryDoc, "traceBack");
        String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(inventoryDoc, "createTime"));
        String inventoryId = VtuzxUtil.getString(inventoryDoc, "_inventoryId");

        Document prdColDoc = prdColDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
        String batchNo = VtuzxUtil.getString(prdColDoc,"batchNo");
        double count = VtuzxUtil.getDouble(prdColDoc,"count");
        String id = VtuzxUtil.getString(prdColDoc,"_id");

        //从外层表中取出物料信息
        Document invenDoc = inventoryDao.findById(inventoryId);
        String materialNo = VtuzxUtil.getString(invenDoc, "materialNo");
        List<VtuzxMap> boxSerialList = new ArrayList<>();//箱子接口唯一码参数
        List<String> traceBackList = new ArrayList<>();//存储整理后的追溯码
        for (Document trace : traceBack) {
            String traceNo = VtuzxUtil.getString(trace, "traceBackNo");
            traceBackList.add(traceNo);
            VtuzxMap traceMap = new VtuzxMap("sn", traceNo);
            boxSerialList.add(traceMap);

        }
        //把唯一码整理成string类型的
        String stringFromList = String.join(",", traceBackList);
        VtuzxMap goodsMap = new VtuzxMap();//getGoodsList方法返回值
        //需要先获取条码(skubarcode)
        VtuzxMap goodsParam = new VtuzxMap();
        goodsParam.append("pageIndex", 0)
                .append("pageSize", 1)
                .append("goodsNo", materialNo);
        try {
            goodsMap = iJiKeYunApiService.getGoodsList(storeDoc, goodsParam);
        } catch (Exception e) {
            throw new VtuzxException(e.getMessage());
        }

        LinkedHashMap result = VtuzxUtil.getObject(goodsMap, "result");
        LinkedHashMap data = VtuzxUtil.getObject((Map<String, Object>) result, "data");
        List<LinkedHashMap> goods = VtuzxUtil.getObject((Map<String, Object>) data, "goods");
        if (goods != null && goods.size() > 0) {
            LinkedHashMap goodsResult = goods.get(0);
            String skuBarcode = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuBarcode");
            String skuId = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuId");
            //传入唯一码
            //查询规格
            Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
            String materialModel = VtuzxUtil.getString(materialDoc, "fSpecification");
            String materialName = VtuzxUtil.getString(materialDoc, "fName");
            VtuzxMap bizcontent = new VtuzxMap();//业务请求参数
            bizcontent.append("goodsNo", materialNo)
                    .append("skuName", materialModel)
                    .append("serialNoList", stringFromList)
                    .append("snDefine1", VtuzxUtil.formatYmdHmsF(new Date()))
                    .append("snDefine2", createTime);//生产日期
            if (!VtuzxUtil.isEmpty(stringFromList)) {
//                try {
//                    iJiKeYunApiService.serialNoAdd(storeDoc, bizcontent);
//                } catch (Exception e) {
//                    throw new VtuzxException(e.getMessage());
//                }
            }
            //创建箱子
            VtuzxMap boxParam = new VtuzxMap();//箱码总参数
            List<VtuzxMap> boxDetailList = new ArrayList<>();//入库申请单明细

            int serialCount = boxSerialList.size();//每个箱子的唯一码数量
            boxDetailList.add(new VtuzxMap("goodsNo", materialNo)
                    .append("goodsName", materialName)
                    .append("skuId", skuId)
                    .append("boxCount", serialCount)
                    .append("snList", boxSerialList));
            boxParam.append("boxCount", 1)
                    .append("boxDetailList", boxDetailList)
                    .append("isAuto", 3)
                    .append("boxNo", billType.barcodeKey() + "|;" + id + "|;" + materialNo + "|;" + batchNo + "|;" + count +"|;" +boxNo);

            if (boxSerialList.size() > 0 && boxSerialList != null) {
                try {
                    iJiKeYunApiService.createBoxBatch(storeDoc, boxParam);
                } catch (Exception e) {
                    throw new VtuzxException(e.getMessage());
                }
            }
        }


    }

    //传入极客云入库单
    private void createInStock(int page,int size) throws Exception{
        String startTime = "2023-05-25 13:49:00";
        String endTime = "2023-05-25 13:49:59";
        Criteria cond = new Criteria("task").is(true);
        cond.and("createTime").gte(VtuzxUtil.parseDate(startTime)).lte(VtuzxUtil.parseDate(endTime));
        Iterator<Document> prdInItr = prdInDao.findList(cond,new Document("createTime",-1),page,size);
        int count = 0;
        List<VtuzxMap> prdInList = new ArrayList<>();//需要上传的
        while (prdInItr.hasNext()){
            count++;
            Document prdInDoc = prdInItr.next();
            String taskBillNo = VtuzxUtil.getString(prdInDoc,"taskBillNo");
            Document taskDoc = prdTaskDetailDao.findOne(Criteria.where("billNo").is(taskBillNo));
            String materialNo = VtuzxUtil.getString(taskDoc,"materialNo");
            if (materialNo.startsWith("04")){
                VtuzxMap map = new VtuzxMap(prdInDoc);
                map.append("materialNo",materialNo);
                prdInList.add(map);
            }
        }
        //获取令牌
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        for (VtuzxMap data: prdInList){
            String stockNo = VtuzxUtil.getString(data,"stockNo");
            String materialNo = VtuzxUtil.getString(data,"materialNo");
            String userName = VtuzxUtil.getString(data,"createUserName");
            double sumCount = VtuzxUtil.getDouble(data,"count");
            String billNo =VtuzxUtil.getString(data,"billNo");
            String inWarehouseCode = "XQWG00101";//仓库编码

            VtuzxMap goodsMap = new VtuzxMap();//getGoodsList方法返回值
            //需要先获取条码(skubarcode)
            VtuzxMap goodsParam = new VtuzxMap();
            goodsParam.append("pageIndex", 0)
                    .append("pageSize", 1)
                    .append("goodsNo", materialNo);
            try {
                goodsMap = iJiKeYunApiService.getGoodsList(storeDoc, goodsParam);
            } catch (Exception e) {
                throw new VtuzxException(e.getMessage());
            }

            LinkedHashMap result = VtuzxUtil.getObject(goodsMap, "result");
            LinkedHashMap dataMap = VtuzxUtil.getObject((Map<String, Object>) result, "data");
            List<LinkedHashMap> goods = VtuzxUtil.getObject((Map<String, Object>) dataMap, "goods");
            LinkedHashMap goodsResult = goods.get(0);
            String skuBarcode = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuBarcode");
            //创建极客云入库单
            VtuzxMap stockParam = new VtuzxMap();//入库参数
            List<VtuzxMap> stockInDetailViews = new ArrayList<>();//入库申请单明细
            stockInDetailViews.add(new VtuzxMap().append("relDetailId", billNo)
                    .append("skuCount", sumCount).append("isCertified", 1)
                    .append("skuBarcode", skuBarcode));
//                    .append("serialList", serialList));
            stockParam.append("inWarehouseCode", inWarehouseCode)//仓库
                    .append("inType", 101)
                    .append("relDataId", billNo)//关联单据编号,可随机，保证不重复即可
                    .append("applyDate", VtuzxUtil.formatYmdHmsF(new Date()))
                    .append("operator", userName)
                    .append("source", "OPEN")
                    .append("notificationCode","100")
                    .append("stockInDetailViews", stockInDetailViews);

            //创建入库单
            try {
                iJiKeYunApiService.createStockIn(storeDoc, stockParam);
            } catch (Exception e) {
                _logger.info(e.getMessage());
            }
        }
        System.out.println(count + "--------------------");
        if (count >= size){
            createInStock(page+1,size);
        }
    }

    //同步单个销售单里的追溯链，(有的单号出库单获取不到唯一码)
    private void serialBlockChain() throws Exception{
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap customerMap = jiKeYunApiService.getSaleBill(storeDoc,
                new VtuzxMap()
                        .append("tradeNo","JY202306271071")
                        .append("pageSize", 50)
                        .append("pageIndex", 0)
                        .append("fields", "tradeFrom,consignTime,goodsSerial.subTradeId,goodsSerial.skuId,goodsSerial.serialNo,warehouseName,warehouseCode,customerCode,goodsDetail.goodsNo,goodsDelivery.productionDate,goodsDelivery.expirationDate,goodsDelivery.batchNo,tradeNo,tradeStatus,warehouseCode,shopName,flagIds,sysFlagIds,flagNames,tradeCount,shareFavourableFee,warehouseCode,goodsDetail.unit,goodsDetail.goodsNo,goodsDetail.goodsName,goodsDetail.specName,goodsDetail.sellCount,goodsDetail.sellPrice,goodsDetail.taxRate,sellerMemo,goodsDelivery.batchNo,goodsSerial.serialNo"));
        Map<String, Object> result = VtuzxUtil.getObject(customerMap, "result");
        Map<String, Object> data = VtuzxUtil.getObject(result, "data");
        List<Map<String, Object>> trades = VtuzxUtil.getObject(data, "trades");

        for (Map<String, Object> trade : trades) {
            String tradeNo = VtuzxUtil.getString(trade,"tradeNo");
            String billNo = IXqcConst.createBillNo(BillType.JKYXS);
            Document oldSaleDoc = jikeyunSaleDao.findOne(Criteria.where("tradeNo").is(tradeNo));
            Document tradeDoc = new Document(trade);
            if (!VtuzxUtil.isEmpty(oldSaleDoc)){//单号已经同步过
                jikeyunSaleDao.updateOne(Criteria.where("tradeNo").is(trade),tradeDoc);
            } else {
                Document saleDoc = new Document(trade);
                saleDoc.append("billNo",billNo)
                        .append("isUpload","no");
                jikeyunSaleDao.insertOne(saleDoc);
            }
            String shopName = VtuzxUtil.getString(trade, "shopName");//店铺名称(销售渠道)
            String consignTime = VtuzxUtil.getString(trade,"consignTime");//发货时间
            List<Map<String,Object>> goodsSerials = VtuzxUtil.getObject(trade,"goodsSerials");
            for (Map<String,Object> serialData :goodsSerials ){
                String serialNo = VtuzxUtil.getString(serialData,"serialNo");
                if (!VtuzxUtil.isEmpty(serialNo)){
                    if (serialNo.startsWith("HTTP://ZS")){
                        StringBuilder sb = new StringBuilder(serialNo.toLowerCase());
                        sb.setCharAt(49,'Z');
                        sb.setCharAt(44,'C');
                        String newSerialNo = sb.toString();
                        Document updateDoc = new Document();
                        updateDoc.append("saleChnnel",shopName)//销售渠道
                                .append("saleTime",consignTime)//发货时间
                                .append("lastTime",consignTime)//最后操作时间
                                .append("tradeNo",tradeNo);
                        traceabilityCodeDetailDao.updateOne(Criteria.where("traceabilityCode").is(newSerialNo),updateDoc);
                        //                    _logger.info(String.format("添加追溯链信息[%s]",serialNo));
                        System.out.println("追溯链" + newSerialNo);

                    }
                }

            }

        }

    }

    /**
     * 同步吉客云存货仓库
     *
     */
    @Override
    public void syncWarehouse(Date from, Date to, int pageIndex) throws Exception{
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap warehouseMap = jiKeYunApiService.getWarehouse(storeDoc,
                new VtuzxMap()
                        .append("pageSize",50)
                        .append("pageIndex",pageIndex));
        Map<String, Object> result = VtuzxUtil.getObject(warehouseMap, "result");
        Map<String,Object> data = VtuzxUtil.getObject(result,"data");
        List<Map<String,Object>> warehouseInfoList = VtuzxUtil.getObject(data,"warehouseInfo");
        if (VtuzxUtil.isEmpty(warehouseInfoList)){
            return;
        }
        List<Document> warehouseList = new ArrayList<>();
        for (Map<String,Object> warehouse : warehouseInfoList){
            String warehouseId = VtuzxUtil.getString(warehouse,"warehouseId");//仓库id
            String warehouseCode = VtuzxUtil.getString(warehouse,"warehouseCode");//仓库编号
            String warehouseName = VtuzxUtil.getString(warehouse,"warehouseName");//仓库名称
            String warehouseTypeName = VtuzxUtil.getString(warehouse,"warehouseTypeName");//仓库类型
            String warehouseCompanyName = VtuzxUtil.getString(warehouse,"warehouseCompanyName");//公司名称
            String warehouseDepartName = VtuzxUtil.getString(warehouse,"warehouseDepartName");//部门名
            String linkMan = VtuzxUtil.getString(warehouse,"linkMan");//联系人
            String tel = VtuzxUtil.getString(warehouse,"tel");//联系电话
            String address = VtuzxUtil.getString(warehouse,"address");//地址
            String memo = VtuzxUtil.getString(warehouse,"memo");//备注
            Document document = new Document();
            document.append("warehouseId",warehouseId)
                    .append("warehouseCode",warehouseCode)
                    .append("warehouseName",warehouseName)
                    .append("warehouseTypeName",warehouseTypeName)
                    .append("warehouseCompanyName",warehouseCompanyName)
                    .append("warehouseDepartName",warehouseDepartName)
                    .append("linkMan",linkMan)
                    .append("tel",tel)
                    .append("address",address)
                    .append("memo",memo);
            warehouseList.add(document);
        }
        //先删除已存在的数据然后添加
        warehouseDao.deleteMany(Criteria.where("warehouseId").in(warehouseList));
        warehouseDao.insertMany(warehouseList);
        syncWarehouse(from,to,pageIndex + 1);
    }

    /**
     * 同步组合装信息
     *
     */
    @Override
    public void syncGoodsPackage(Date from, Date to, int pageIndex) throws Exception{
        VtuzxMap sysParamMap = getParameters(new VtuzxMap("keys", new VtuzxArrayList<>("traceabilityCodeUrl")));
        VtuzxMap traceabilityCodeUrlMap = VtuzxUtil.getObject(sysParamMap, "traceabilityCodeUrl");
        if (traceabilityCodeUrlMap == null) {
            throw new VtuzxException(IXqcConst.Msg_E_system);
        }
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap goodsPackageMap = jiKeYunApiService.getGoodsPackage(storeDoc,
                new VtuzxMap()
                        .append("lastModifiedStart", VtuzxUtil.formatYmdHmsF(from))
                        .append("lastModifiedEnd", VtuzxUtil.formatYmdHmsF(to))
                        .append("pageSize", 50)
                        .append("pageIndex", pageIndex));
        Map<String, Object> result = VtuzxUtil.getObject(goodsPackageMap, "result");
        List<Map<String, Object>> goodsPackage = VtuzxUtil.getObject(result, "data");
        if (goodsPackage.size() <= 0) {
            return;
        }
        for (Map<String, Object> goodsPackageList : goodsPackage) {
            Long skuId = VtuzxUtil.getLong(goodsPackageList, "skuId");//规格ID
            Long goodsId = VtuzxUtil.getLong(goodsPackageList, "goodsId");//货品ID
            String goodsNo = VtuzxUtil.getString(goodsPackageList, "goodsNo");//货品编码
            String goodsName = VtuzxUtil.getString(goodsPackageList, "goodsName");//货品名称
            String unitName = VtuzxUtil.getString(goodsPackageList, "unitName");//单位名称
            List<Map<String, Object>> goodsPackageDetail = VtuzxUtil.getObject(goodsPackageList, "goodsPackageDetail");//子件信息
            Document goodsPackageDoc = new Document();
            goodsPackageDoc.append("skuId", skuId)
                    .append("goodsId", goodsId)
                    .append("goodsNo", goodsNo)
                    .append("goodsName", goodsName)
                    .append("unitName", unitName)
                    .append("goodsPackageDetail", goodsPackageDetail);
            Document jackGoodsPackage = goodsPackageDao.findOne(Criteria.where("goodsNo").is(goodsNo));
            if (VtuzxUtil.isEmpty(jackGoodsPackage)) {//如果没添加过
                goodsPackageDao.insertOne(goodsPackageDoc);//添加到极客云调拨表
                _logger.info(String.format("添加组合装货品%s", goodsNo));
            } else {
                goodsPackageDao.updateOne(Criteria.where("goodsNo").is(goodsNo), goodsPackageDoc);
                _logger.info(String.format("修改组合装货品%s", goodsNo));
            }
        }
        syncGoodsPackage(from, to, pageIndex + 1);
    }

    /**
     * 同步入库信息
     *
     */
    @Override
    public void syncStorageGoodsdocin(Date from, Date to, int pageIndex) throws Exception{
        VtuzxMap sysParamMap = getParameters(new VtuzxMap("keys", new VtuzxArrayList<>("traceabilityCodeUrl")));
        VtuzxMap traceabilityCodeUrlMap = VtuzxUtil.getObject(sysParamMap, "traceabilityCodeUrl");
        if (traceabilityCodeUrlMap == null) {
            throw new VtuzxException(IXqcConst.Msg_E_system);
        }
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap storageGoodsdocinMap = jiKeYunApiService.getStorageGoodsdocin(storeDoc,
                new VtuzxMap()
                        .append("startDate", VtuzxUtil.formatYmdHmsF(from))
                        .append("endDate", VtuzxUtil.formatYmdHmsF(to))
                        .append("pageSize", 50)
                        .append("pageIndex", pageIndex)
                        .append("selelctFields", "recId, goodsdocNo, billNo, inOutDate, gmtCreate, sourceBillNo"));
        Map<String, Object> result = VtuzxUtil.getObject(storageGoodsdocinMap, "result");
        List<Map<String, Object>> storageGoodsdocin = VtuzxUtil.getObject(result, "data");
        if (storageGoodsdocin.size() <= 0) {
            return;
        }
        for (Map<String, Object> storageGoodsdocinList : storageGoodsdocin) {
            Long recId = VtuzxUtil.getLong(storageGoodsdocinList, "recId");//入库单ID
            String goodsdocNo = VtuzxUtil.getString(storageGoodsdocinList, "goodsdocNo");//入库单号
            String billNo = VtuzxUtil.getString(storageGoodsdocinList, "billNo");//上游单据号(关联单号)
            String inOutDate = VtuzxUtil.getString(storageGoodsdocinList, "inOutDate");//入库时间
            String gmtCreate = VtuzxUtil.getString(storageGoodsdocinList, "gmtCreate");//创建时间
            String sourceBillNo = VtuzxUtil.getString(storageGoodsdocinList, "sourceBillNo");//来源单号
            Document StorageGoodsdocinDoc = new Document();
            StorageGoodsdocinDoc.append("recId", recId)
                    .append("goodsdocNo", goodsdocNo)
                    .append("billNo", billNo)
                    .append("inOutDate", inOutDate)
                    .append("gmtCreate", gmtCreate)
                    .append("sourceBillNo", sourceBillNo);
            Document jackStorageGoodsdocin = storageGoodsdocinDao.findOne(Criteria.where("goodsdocNo").is(goodsdocNo));
            if (VtuzxUtil.isEmpty(jackStorageGoodsdocin)) {//如果没添加过
                storageGoodsdocinDao.insertOne(StorageGoodsdocinDoc);//添加到入库表
                _logger.info(String.format("添加入库信息%s", goodsdocNo));
            } else {
                storageGoodsdocinDao.updateOne(Criteria.where("goodsdocNo").is(goodsdocNo), StorageGoodsdocinDoc);
                _logger.info(String.format("修改入库信息%s", goodsdocNo));
            }
        }
        syncStorageGoodsdocin(from, to, pageIndex + 1);
    }

    /**
     * 获取吉克云待同步调拨单
     *
     * @param from
     * @param to
     * @param pageIndex
     */
    @Override
    public void syncAllocationTask(Date from, Date to, int pageIndex) throws Exception {
        VtuzxMap sysParamMap = getParameters(new VtuzxMap("keys", new VtuzxArrayList<>("traceabilityCodeUrl")));
        VtuzxMap traceabilityCodeUrlMap = VtuzxUtil.getObject(sysParamMap, "traceabilityCodeUrl");
        if (traceabilityCodeUrlMap == null) {
            throw new VtuzxException(IXqcConst.Msg_E_system);
        }
        //获取吉克云调拨单数据
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap customerMap = jiKeYunApiService.allocationList(storeDoc,
                new VtuzxMap("modifyStartDate", VtuzxUtil.formatYmdHmsF(from))//修改时间起始
                        .append("modifyEndDate", VtuzxUtil.formatYmdHmsF(to))//修改时间结束
                        .append("pageSize", 50)
                        .append("outstatus", "3")//出库状态已完成
                        .append("pageIndex", pageIndex));
        Map<String, Object> result = VtuzxUtil.getObject(customerMap, "result");
        Map<String, Object> data = VtuzxUtil.getObject(result, "data");
        List<Map<String, Object>> stockAllocateList = VtuzxUtil.getObject(data, "stockAllocate");
        if (stockAllocateList.size() <= 0) {
            return;
        }
        /*Calendar calendar = Calendar.getInstance();
        calendar.set(2025, Calendar.SEPTEMBER, 1, 0 ,0, 0);
        Date from1 = calendar.getTime();
        calendar.set(2025, Calendar.SEPTEMBER, 1, 23 ,59, 59);
        Date to1 = calendar.getTime();*/
        //中台保存
        for (Map<String, Object> stockAllocate : stockAllocateList) {
            String allocateNo = VtuzxUtil.getString(stockAllocate, "allocateNo");//调拨单号
            String outWarehouseCode = VtuzxUtil.getString(stockAllocate, "outWarehouseCode");//调出仓库编号
            long gmtModified = VtuzxUtil.getLong(stockAllocate, "gmtModified");//修改时间
            String intWarehouseCode = VtuzxUtil.getString(stockAllocate, "intWarehouseCode");//调入仓库编号
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date inOutDate = dateFormat.parse(storageGoodsdocinDao.getInOutDateBySourceBillNo(allocateNo));
            //保存到待同步单据列表
            _logger.info("判断数据是否满足待同步条件");
            if (isSpecialWarehouse(outWarehouseCode, intWarehouseCode) && inOutDate.getTime() > from.getTime() && inOutDate.getTime() < to.getTime()) {
                _logger.info("保存数据到待同步表");
                Document syncTaskDoc = new Document()
                        .append("billTaskNo", allocateNo)
                        .append("orderType", "调拨单")
                        .append("orderTime", new Date(gmtModified))
                        .append("isUpload", "no")
                        .append("errorMsg", "-");
                //在待同步列表查询此调拨单
                Document existingTask = syncTaskDao.findOne(
                        Criteria.where("billTaskNo").is(allocateNo)
                );
                //在已同步列表查询此调拨单
                Document existingTaskHistory = syncTaskHistoryDao.findOne(
                        Criteria.where("billTaskNo").is(allocateNo)
                );
                //待同步列表和已同步列表都没有此调拨单(未获取过也未同步过此调拨单的情况)
                if (VtuzxUtil.isEmpty(existingTask) && VtuzxUtil.isEmpty(existingTaskHistory)) {
                    syncTaskDao.insertOne(syncTaskDoc);
                    _logger.info("新增待同步列表调拨单：" + allocateNo);
                    //待同步列表有此调拨单,已同步列表没有此调拨单(获取过此调拨单,但由于各种原因未同步或未同步成功的情况)
                } else if(!VtuzxUtil.isEmpty(existingTask) && VtuzxUtil.isEmpty(existingTaskHistory)){
                    syncTaskDao.updateOne(
                            Criteria.where("_id").is(existingTask.getObjectId("_id")),
                            syncTaskDoc
                    );
                    _logger.info("更新待同步表调拨单：" + allocateNo);
                    //其他情况(1.待同步列表没有此调拨单,已同步列表有此调拨单(此单据已同步的标准情况) 2.待同步列表和已同步列表都有此调拨单(不应存在此情况))
                } else {
                    _logger.info("此调拨单已同步：" + allocateNo);
                }
            } else {
                _logger.info("跳过不满足待同步条件调拨单: " + allocateNo + " (仓库: " + outWarehouseCode + "=>" + intWarehouseCode + ")");
            }
            //从stockAllocate对象中获取名为stockAllocateDetailViews对象,以List类型集合存储
            List<Map<String, Object>> goodsDetails = VtuzxUtil.getObject(stockAllocate, "stockAllocateDetailViews");
            //遍历商品详情列表,对每个商品进行处理
            for (Map<String, Object> goods : goodsDetails) {
                //从商品中获取商品编号
                String selfProductNo = VtuzxUtil.getString(goods, "goodsNo");
                //判断是否为自采品
                if (selfProductDao.isSelfProduct(selfProductNo)) {
                    //如果是自采品,将调拨单号和商品编号插入记录
                    selfProductBillDao.insertSelfProductBill(allocateNo, selfProductNo);
                }
            }
        }
        syncAllocationTask(from,to,pageIndex + 1);
    }

    /**
     * 获取吉克云待同步销售单
     *
     * @param from
     * @param to
     * @param pageIndex
     */
    @Override
    public void syncSaleTask(Date from, Date to, int pageIndex) throws Exception {
        _logger.info(String.format("导入%s - %s的销售数据", VtuzxUtil.formatYmdHmsF(from), VtuzxUtil.formatYmdHmsF(to)));
        List<Integer> allowedTradeStatus = Arrays.asList(9090, 6000);//单据状态已完成和单据状态发货在途
        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        VtuzxMap saleMap = jiKeYunApiService.getSaleBill(storeDoc,
                new VtuzxMap("startConsignTime", from)//发货时间（起始）
                        .append("endConsignTime", to)//发货时间（截止）
                        .append("tradeStatus", allowedTradeStatus)
                        .append("pageIndex", pageIndex)
                        .append("fields", "completeTime,couponFee,companyName,consignTime,isFit,tradeFrom,goodsSerial.subTradeId," +
                                "goodsSerial.skuId,goodsSerial.serialNo,warehouseName,warehouseCode,customerCode," +
                                "goodsDetail.goodsNo,goodsDetail.shareFavourableAfterFee,goodsDelivery.productionDate,goodsDelivery.expirationDate," +
                                "goodsDelivery.batchNo,tradeNo,tradeStatus,shopName,flagIds,sysFlagIds," +
                                "flagNames,tradeCount,shareFavourableFee,goodsDetail.unit," +
                                "goodsDetail.goodsName,goodsDetail.specName,goodsDetail.sellCount,departName," +
                                "goodsDetail.sellPrice,goodsDetail.taxRate,sellerMemo,gmtCreate,tradeTime,invoiceStatus,seller," +
                                "onlineTradeNo,appendMemo,buyerMemo,otherFee,discountFee,isGift,goodsMemo"));
        System.out.println(pageIndex);
        Map<String, Object> result = VtuzxUtil.getObject(saleMap, "result");
        String tradeString = VtuzxUtil.getString(result,"data");
        if (VtuzxUtil.isEmpty(tradeString)){
            return;
        }
        Map<String,Object> tradeData = JSON.parseObject(tradeString,new TypeReference<HashMap<String,Object>>(){});
        JSONArray jsonArray = VtuzxUtil.getObject(tradeData,"Trades");
        List<String> tradeNoList = new ArrayList<>();//销售单号集合单集合
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonTrades = (JSONObject) jsonArray.get(i);
            //吉客云的json首字母变成了大写,转成小写
            Map<String, Object> tradeMap = new HashMap<>();
            for (String key : jsonTrades.keySet()) {
                String modifyKey = key.substring(0, 1).toLowerCase() + key.substring(1);
                tradeMap.put(modifyKey, jsonTrades.get(key));
            }
            String tradeNo = VtuzxUtil.getString(tradeMap, "tradeNo");
            if (!tradeNoList.contains(tradeNo)) {
                tradeNoList.add(tradeNo);
            }
            Document tradeDoc = new Document(tradeMap);
            String warehouseName = VtuzxUtil.getString(tradeDoc, "warehouseName");
            String stockId = getStockId(warehouseName, storeDoc);
            tradeDoc.append("stockId", stockId);
            String consignTime = VtuzxUtil.getString(tradeDoc, "consignTime");//发货日期
            String tradeCount = VtuzxUtil.getString(tradeDoc, "tradeCount");//货品数量
            Date consignDate = VtuzxUtil.parseDate(consignTime);
            tradeDoc.remove("consignTime");
            tradeDoc.append("consignTime", consignDate);
            if (consignDate.getTime() > from.getTime() && consignDate.getTime() < to.getTime() && !tradeCount.equals("0")) {
                //获取销售渠道名称
                String shopName = VtuzxUtil.getString(tradeDoc, "shopName");
                //根据销售渠道名称获取公司名称
                String company = channelDao.getCompanyByName(shopName);
                //保存到待同步单据列表
                _logger.info("判断数据是否满足待同步条件");
                boolean notProcess = ("大连晓芹食品有限公司".equals(company));
                boolean notProcessWB = (shopName.startsWith("外埠"));
                boolean notProcessSY = (shopName.endsWith("收银"));
                if (notProcess || notProcessWB || notProcessSY) {
                    _logger.info("跳过销售渠道不符合待同步条件的销售单: "
                            + shopName + " (销售渠道: " + shopName + ")"
                            + tradeNo + " (销售渠道所属公司: " + company + ")");
                } else {
                    if (consignDate.getTime() > from.getTime() && consignDate.getTime() < to.getTime()) {
                        //构建集合文档
                        Document syncTaskDoc = new Document()
                                .append("billTaskNo", tradeNo)    // 销售单号
                                .append("orderType", "销售单")     // 固定值
                                .append("orderTime", consignDate) // 发货时间
                                .append("isUpload", "no");
                        //在待同步列表查询此销售单
                        Document existingTask = syncTaskDao.findOne(
                                Criteria.where("billTaskNo").is(tradeNo)
                        );
                        //在已同步列表查询此销售单
                        Document existingTaskHistory = syncTaskHistoryDao.findOne(
                                Criteria.where("billTaskNo").is(tradeNo)
                        );
                        //待同步列表和已同步列表都没有此销售单(未获取过也未同步过此销售单的情况)
                        if (VtuzxUtil.isEmpty(existingTask) && VtuzxUtil.isEmpty(existingTaskHistory)) {
                            syncTaskDao.insertOne(syncTaskDoc);
                            _logger.info("新增待同步列表销售单：" + tradeNo);
                            //待同步列表有此销售单,已同步列表没有此销售单(获取过此销售单,但由于各种原因未同步或未同步成功的情况)
                        } else if(!VtuzxUtil.isEmpty(existingTask) && VtuzxUtil.isEmpty(existingTaskHistory)){
                            syncTaskDao.updateOne(
                                    Criteria.where("_id").is(existingTask.getObjectId("_id")),
                                    syncTaskDoc
                            );
                            _logger.info("更新待同步表销售单：" + tradeNo);
                            //其他情况(1.待同步列表没有此销售单,已同步列表有此销售单(此单据已同步的标准情况) 2.待同步列表和已同步列表都有此销售单(不应存在此情况))
                        } else {
                            _logger.info("此销售单已同步：" + tradeNo);
                        }
                        //从tradeDoc对象中获取名为goodsDetail对象,以Document类型集合存储
                        List<Map<String, Object>> goodsDetails = VtuzxUtil.getObject(tradeDoc, "goodsDetail");
                        //遍历商品详情列表,对每个商品进行处理
                        for (Map<String, Object> goods : goodsDetails) {
                            //从商品中获取商品编号
                            String selfProductNo = VtuzxUtil.getString(goods, "goodsNo");
                            //判断是否为自采品
                            if (selfProductDao.isSelfProduct(selfProductNo)) {
                                //如果是自采品,将销售单号和商品编号插入记录
                                selfProductBillDao.insertSelfProductBill(tradeNo, selfProductNo);
                            }
                        }
                    }
                }
            } else {
                System.out.println("跳过单据:" + tradeNo + "======" + "发货时间:" + consignDate.getTime());
            }
        }
        syncSaleTask(from,to,pageIndex + 1);
    }
}